Compare commits

..

637 Commits

Author SHA1 Message Date
Michael Bradshaw
af81f26025 Fix MSVC warning about 2147483648 not fitting in an int
This also cleans up some of the documentation. I'm not sure what happened to that last line.

BUG=webm:1501

Change-Id: Ie0ff0607ebb60d033e7ad40bdc7943c0a6bd6783
2018-03-05 09:51:48 -08:00
Michael Bradshaw
2374a6f0a0 Fix compilation with MSVC
BUG=webm:1499

Change-Id: I8e63496a287b6303c287fd2254d4267c79f32f13
2018-02-28 14:32:16 -08:00
Tom Finegan
59f08602fc Allow shared builds of libwebm.
Omit the STATIC in the add_library command, and stop
forcing static MSVC runtimes when BUILD_SHARED_LIBS
is enabled.

$ cmake path/to/libwebm -DBUILD_SHARED_LIBS=1 && cmake --build .

Change-Id: I4935c774d98f70a39363f37be4f9e8989a0749c0
2018-02-06 14:30:18 -08:00
James Zern
faf76029b0 Merge "vp9_header_parser: make SetFrame private" 2018-02-02 19:46:59 +00:00
Tom Finegan
8e88e04b07 webm2pes: Avoid OOB reads caused by invalid superframe index.
BUG=webm:1492

Change-Id: Ibd5781731fe8f6fcdf5f1cc6e5807d17b3b92d4d
2018-02-02 07:06:43 -08:00
James Zern
a5837e4dd0 vp9_header_parser: make SetFrame private
and call it from ParseUncompressedHeader. this avoids attempts to parse
a stale buffer should SetFrame fail.

BUG=webm:1493

Change-Id: I441ae9d0db3f0a01d73902a8f5b06812e2e93422
2018-02-02 00:39:52 -08:00
Tom Finegan
6ab4f8fa97 Limit string element size to 20 million bytes.
Avoids crashes in allocators when fuzzers or maliciously
crafted streams make elements appear extremely large.

BUG=b/68352235

Change-Id: I71c293d8abdff0d188a881c4366bc09182ac32f8
2018-01-30 15:00:40 -08:00
Tom Finegan
12b42e9920 Merge "Replace uses of deprecated std::auto_ptr with std::unique_ptr." 2018-01-24 20:57:01 +00:00
Lisa Velden
d707c67276 Replace uses of deprecated std::auto_ptr with std::unique_ptr.
Change-Id: I8d67fc6f3ce168f4d8b6330549f766dbf5374d61
2018-01-24 11:37:37 +01:00
Michael Bradshaw
8f638df2c3 Set a maximum limit on element recursion depth
The maximum recursion depth is set to 25. If that's not sufficient for
someone's needs, they're welcome to submit a patch that makes it
configurable.

This fixes a stack overflow found by AutoFuzz. The stack overflow was
caused by recursing too much. I've included the fuzzer's test cases in
the fuzzing/corpus directory. I've also created two (one for SimpleTag
and ChapterAtom each) additional test files, each comprised of 10,000
recursively nested elements. Manually running the fuzzer (with ASan and
UBSan) shows all inputs are now handled correctly, and no stack
overflows occur.

Change-Id: I8514259fd0788e71a58e3ccce2a0fb8a3523acfc
2018-01-22 13:50:14 -08:00
Tom Finegan
1653953c39 Silence -Wdeprecated-declarations in GCC 4.7+.
Change-Id: I63a8bdb0649452a8e50b579f61bc4ea5d7e294f7
2017-12-18 11:35:40 -08:00
Hui Su
9e37f34e48 Update VP9 level definition
Add luma picture max width and height constraint.

BUG=b/65412009

Change-Id: I25545eb632b29c4241e335896e6f284102e27623
2017-12-07 16:34:18 -08:00
Michael Bradshaw
b03c65468b Merge "webm_parser: Add new enum values" 2017-11-03 22:36:14 +00:00
Michael Bradshaw
8f709400a2 webm_parser: Add new enum values
For the new stereo mode, see https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md#webm-matroska
For the new color primaries, see ISO/IEC 23001-8:2016

Change-Id: I92c2bb0fedc2b1895d893ad55095d29c811c0dcf
2017-11-03 11:41:03 -07:00
Tom Finegan
7dd0b80931 Avoid overflows in Block::GetTimeCode().
BUG=b/66854237

Change-Id: I721bfa0579597995ae0b488f69bcf17aba6c32c6
2017-09-30 12:14:05 -07:00
Tom Finegan
7baf4cb898 Merge "Fix include-what-you-use warning in common/file_util.cc." 2017-09-19 18:40:18 +00:00
Tom Finegan
e590bc2d5a Fix include-what-you-use warning in common/file_util.cc.
Add include for <string>.

Change-Id: I053fb2e6e36889e819703c601b2df8c6d313817f
2017-09-19 11:38:58 -07:00
Tom Finegan
fbc8ab96da Improve mingw support.
- Remove existing mingw-w64 toolchain file.
- Add x86 and x86_64 mingw-w64 toolchain files.
- Add gtest mingw work around (disable gtest cmake and build
  our own static lib).

Change-Id: Ic602df62f5485ccbd79deccf3aed2a4d35fef8ad
2017-09-18 13:19:36 -07:00
Tom Finegan
27eb0b9002 Fix builds with mingw x86 and x86_64.
- Deal with tmpnam_s() preproc issues in file_util.cc
  when building with mingw-w64..
- Add stdint.h include in mkvmuxer.cc.

Change-Id: I819a27e6d805d772a6e1863982a2eeafd27b2a0d
2017-09-18 13:19:17 -07:00
clang-format
22de626018 apply clang-format
Change-Id: I27aaabefca7e01a7762f50a17fb9219c19d82f1b
2017-08-27 18:33:01 -07:00
James Zern
960b81e356 .clang-format: update to 4.0.1
based on Google style with the following differences:
3a4
> # Generated with clang-format 4.0.1
10c11
< AlignTrailingComments: true
---
> AlignTrailingComments: false
15,16c16,17
< AllowShortIfStatementsOnASingleLine: true
< AllowShortLoopsOnASingleLine: true
---
> AllowShortIfStatementsOnASingleLine: false
> AllowShortLoopsOnASingleLine: false
23c24
< BraceWrapping:
---
> BraceWrapping:
37c38
< BreakBeforeTernaryOperators: true
---
> BreakBeforeTernaryOperators: false
51c52
< IncludeCategories:
---
> IncludeCategories:

Change-Id: I692c52b9d8c8421a9fc3097705763423a1437800
2017-08-27 18:32:45 -07:00
Vignesh Venkatasubramanian
86fa6dc2cb mkvparser: Fix potential overflow in Block::Parse
BUG=b/65045341

Change-Id: I198e72ea3859d2382a34e1e6dca957f9323af278
2017-08-25 11:28:01 -07:00
Vignesh Venkatasubramanian
245e7a258a mkvparser: Fix integer overflow in Block::GetTime
tc * scale could overflow theoretically (as it did in a fuzzed
file). The return -1 isn't really well defined, but that'll
probably do given this this is an extreme outlier case.

BUG=b/64953172

Change-Id: Id4aba673c3f85dee6ee25cc5f4b2db73b30ca8b3
2017-08-23 12:12:19 -07:00
Neil Birkbeck
2e76d22782 Add command line support for projection_type
Add command line for projection_type, projection_pose_{yaw,pitch,roll}.
Use a file for projection_private data to allow setting the contents
for cubemap, equirect, or mesh.

Change-Id: I45f20c68a5d01150d0fb3882ad1c587a8b9f63f2
2017-08-07 18:15:01 -07:00
Tom Finegan
9af1e59995 Avoid float overflows due to casts of out of range values.
BUG=b/37478056

Change-Id: I4eb9e6be25de6c682a252c7a1252ef040edd9eb1
2017-07-28 14:19:07 -07:00
Jerome Jiang
0ae757087f Fix android build failure with NDK r15b.
BUG=webm:1447

Change-Id: I8defe45cb94eb9c209ba72ce446786f24c14c0b8
2017-07-17 14:00:18 -07:00
James Zern
a97c484bfd Merge "disable -Wdeprecated-declarations in legacy code" 2017-06-22 02:02:16 +00:00
James Zern
90967863b2 mkvparser: fix float conversion warning
Change-Id: I2b79a6af431f9c51e5c32c75da18645674ebbb4d
2017-06-20 19:20:01 -07:00
James Zern
84e82579f7 disable -Wdeprecated-declarations in legacy code
this avoids downstream projects from needing to add this flag to their
build.

BUG=webm:1445

Change-Id: I03f3cc20496bc52245b6c3c013ae3c13936f4b4f
2017-06-20 19:18:42 -07:00
James Zern
a98f4950f6 AddGenericFrame: fix memory leak on failure
quiets a static analysis warning

Change-Id: I9fac3c495beefb0a76d0476573b95700662e082c
2017-05-01 18:50:20 -07:00
James Zern
da131dd350 AddCuePoint: fix memory leak on failure
quiets a static analysis warning

Change-Id: I288ab6216ecd066f7d6542a7465db1f182859c32
2017-05-01 15:18:38 -07:00
James Zern
b0cea9ce24 Add(Audio|Video)Track: fix memory leak on failure
quiets a static analysis warning

Change-Id: Iaa6909e94deae81ace3e65f37ab746d72031620f
2017-05-01 15:17:30 -07:00
Tom Finegan
a65b9e0287 Merge changes I7e467d31,Ia8633cab
* changes:
  Add test for projection parse failures.
  Add test for primary chromaticity parse failures.
2017-04-28 22:42:04 +00:00
James Zern
5261a679b7 webm_info: check vp9 ParseUncompressedHeader return
avoids potential side effects

BUG=webm:1416,webm:1417

Change-Id: I4acd4c9f86be20fa3c06af6c87c1ce538a50c84c
2017-04-21 15:16:17 -07:00
James Zern
85f7e2e428 webm_info,PrintVP9Info: validate alt ref sizes
fixes out of bounds reads with corrupted bitstreams

BUG=webm:1416,webm:1417

Change-Id: Ia643708b4b74d153a7b1dee1c4cbcab7f79d7111
2017-04-21 15:15:26 -07:00
James Zern
9b97ca197d vp9_header_parser_tests: check parser return
ensure ParseUncompressedHeader() succeeds with valid bitstreams

Change-Id: I1e3900fc08f3b6b2e86bc2f59fd8fd96bc26ad0f
2017-04-21 15:15:26 -07:00
James Zern
300d6d8719 CuePoint::Find: check Track pointer
replace assert with a check of the pointer, this is a public function so
should be tolerant of invalid parameters

BUG=webm:1415

Change-Id: I28a3a2ef905d62f11928dbbe54c119411d2b1f74
2017-04-19 23:24:27 -07:00
James Zern
50c44bb44d webm_info,OutputCues: fix indexing of tracks
use GetTrackByIndex() rather than GetTrackByNumber(). the former is
0-based the latter is by track id, this loop iterates through all tracks
based on the track count.
fixes a segfault with tracks non-starting at 1 / increasing by 1.

BUG=webm:1415

Change-Id: I916328575d0871cf4090b1d123644d6f01e6ffb1
2017-04-19 23:10:33 -07:00
James Zern
a0d27f0d51 mkvparser,Block::Parse: remove incorrect assert
this path has been error checked since:
986b64b mkvparser: Add error checking in Block::Parse.

BUG=webm:1405

Change-Id: I1c17c05076455f25ab888555d71d7b27c032e9dd
2017-04-18 12:45:43 -07:00
James Zern
784fc1bb7c vttdemux,CloseFiles: check file pointer before closing
BUG=webm:1405

Change-Id: I7729277c632d40d478aa80ca6a009f95038196fb
2017-04-17 15:55:17 -07:00
Tom Finegan
c59278c4b4 Merge ".gitattributes: force mkv/webm to be treated as binary" 2017-04-12 15:55:58 +00:00
James Zern
b4522c1cdf .gitattributes: force mkv/webm to be treated as binary
Change-Id: I91463cd9b709dcfbb4aedc128b89f98f40550f69
2017-04-11 12:45:30 -07:00
Tom Finegan
a118f3d570 Add test for projection parse failures.
Specifically for failures due a value too large to express as float.

BUG=b/36454364

Change-Id: I7e467d31ec49d865bc346b45d122411d13a74f76
2017-04-10 10:00:28 -07:00
Tom Finegan
d39847954d Add test for primary chromaticity parse failures.
Specifically for failures due to field size being too large.

BUG=webm:1381

Change-Id: Ia8633cab96d10ab485de1ab796a643e3c26a9923
2017-04-10 09:54:17 -07:00
Tom Finegan
9bbec4c905 Fix permissions on test file.
Change-Id: I062b685899e9125a4da29914357a494d2c63e256
2017-04-10 09:32:51 -07:00
James Zern
2cef4d51a2 mkvparser:Parse: s/FLT_MIN/-FLT_MAX/
FLT_MIN is the smallest finite value (numeric_limits::min()) -FLT_MAX is
the correct for the most negative (numeric_limits::lowest())

http://en.cppreference.com/w/cpp/types/numeric_limits

BUG=b/36255773
BUG=webm:1381

Change-Id: Iaaff611acffc3df28fef12af81ac5299791f0148
2017-03-23 16:27:41 -07:00
Vignesh Venkatasubramanian
35a3c88728 mkvmuxer: Turn off estimate_file_duration_ by default
Users who want this feature can explicitly turn it on. Since it
involves estimating, it should be off by default.

Change-Id: I3e934169d19b68a276c21d694179350c5b315a5a
2017-03-23 12:27:48 -07:00
Tom Finegan
5a418303e3 mkvparser: Avoid double free when Chromaticity parse fails.
PrimaryChromaticity::Parse never owns the PrimaryChromaticity
it allocates-- avoid freeing it because doing so results in a
double free when the MasteringMetadata dtor runs.

BUG=webm:1381

Change-Id: Ief0159f6ab667234e3fdc51c65f23ef5efb32a71
2017-03-21 10:44:09 -07:00
Tom Finegan
67e3ffa908 mkvparser: Avoid casts of values too large for float in Projection elements.
Return a parse error when values are out of range.

BUG=b/36255773

Change-Id: I977c41c9108b97592f3707bf8c01373cf36f2365
2017-03-20 14:03:19 -07:00
James Zern
87bcddf0e5 vttdemux::ChapterAtomParser: check for NULL display string
prevents segfault due to strlen(NULL)

BUG=webm:1382

Change-Id: I536663e287d151e11bf7074349a34d922cb9856a
2017-03-09 12:50:41 -08:00
Vignesh Venkatasubramanian
992a330ec0 Merge "Update .gitignore" 2017-03-08 02:41:03 +00:00
Vignesh Venkatasubramanian
a534a24f58 Update .gitignore
Update .gitignore to reflect recent changes in binary names.

Change-Id: I4c010c5b948a2824c259fac37ad812be19d9e200
2017-03-07 13:53:44 -08:00
Vignesh Venkatasubramanian
a0d67d081c mkvmuxer: Fix hard-coded data size in EbmlElementSize
EbmlElementSize for char* assumes that the varint encoding of
payload size is always 1-byte. Fix that by using the correct
number of bytes.

mkvinfo of the new gold file: http://pastebin.com/ncR7DqEf

Change-Id: I2d10708de77b2b8089900a8719ee3797dfb6994c
2017-03-07 11:42:16 -08:00
KO Myung-Hun
c36112caa0 mkvparser: #include sys/type.h
On OS/2, off_t requires sys/types.h.

Change-Id: Ic307347a62754b0b6d940c4d89228038f5f4e84b
2017-02-01 20:13:14 +00:00
Tom Finegan
686664eba2 Fix cmake generation warnings on Windows.
A target must exist before its properties can be set. Defer
libwebm target rename on windows until after creation of the
webm library target.

Change-Id: I29c5e90f1f653a00ff156316c03b0ffd78e9a998
2017-01-26 07:57:32 -08:00
Tom Finegan
2b2c196558 cmake: Fix required flag check.
It always passed after first test due to lack of CACHE in unset()
call. Also:

- Fix flag name in error message.
- Use actual flag instead of hard coded -std=c++11

Change-Id: I29c0dc4fd0f5ce97f658919a5739e15831a00281
2017-01-23 10:58:45 -08:00
Tom Finegan
4494ce468a Merge "Cmake refactor." 2017-01-19 23:50:26 +00:00
Tom Finegan
166e40fa97 Cmake refactor.
- Split sources from targets. Source files are stored in list variables,
  and targets now use the list vars.
- Surface all build settings control in CMakeLists.txt.
- Remove individual C++11 tests in favor of requiring support
  for --std=c++11.
- Improve organization; stop reopening the same if's.

Change-Id: I1989803fdfd9c032f417a5fc12985671455148bd
2017-01-19 08:40:31 -08:00
Tom Finegan
9fb774ab80 Add missing include in webm2pes.cc.
We need <algorithm> on some platforms.

Change-Id: I65fa3ad52265b05c4141e14d97d6de0af1649b29
2017-01-18 07:26:30 -08:00
Tom Finegan
4956b2dec6 mkvmuxer: Force new clusters when audio queue gets too long.
Force creation of a new Cluster when writing queued audio would
cause an error due to violating maximum block duration.

BUG=675521

Change-Id: I6ad09c2a2f71d95bb04eed5ead04dc8072aaa59d
2017-01-12 13:15:46 -08:00
Tom Finegan
54f155986d cmake: Cache results of CXX flag tests.
Avoid re-testing to improve cmake build and regen speed.

Change-Id: I8e2fe6601036cc7d176cdc3738616261a2da408b
2016-11-14 19:45:51 -08:00
Tom Finegan
81c73fc78e mkvparser: Avoid alloc failures in SeekHead::Parse.
Some run times return NULL pointers when creating 0 length
arrays. Avoid the inconsistency by skipping allocation when
the length of the SeekHead entry or void element array
is 0.

BUG=webm:1313

Change-Id: I28b4eac1d3e0ba968147637883f6e37c089e8573
2016-10-31 12:11:56 -07:00
James Zern
9732ae991e EbmlElementSize: quiet uint64->int32 conv warning
Change-Id: I189c3a3ee2f946034a5f7ad1bd5e1d0a301d24c0
2016-10-18 15:31:17 -07:00
James Zern
da04ebae9b SetProjectionPrivate: quiet uint64->size_t conv warning
Change-Id: Iae467f650770e98ef59fede6d714e222b502f5bb
2016-10-18 15:30:48 -07:00
James Zern
5e1d131e6c Merge "mkvparser,Projection::Parse: fix int->bool conv" 2016-10-18 22:13:09 +00:00
James Zern
6db32d5f6e mkvparser,Projection::Parse: fix int->bool conv
this would have incorrectly returned true on parse failure

Change-Id: I1ae6fc2aae09491aa3cda47a5414529fc7a3848f
2016-10-17 23:34:06 -07:00
James Zern
3bb0dfae6a cosmetics: fix a couple lint warnings
remove trailing ';' and s/const static/static const/

Change-Id: Id5587b057a8e2b088eac8538d8e2b5e9053fdcf4
2016-10-17 18:28:38 -07:00
James Zern
0e179d683e update .clang-format
generated by version 3.8.1
local changes from --style=Google

3a4
> # Generated with clang-format 3.8.1
10c11
< AlignTrailingComments: true
---
> AlignTrailingComments: false
15,16c16,17
< AllowShortIfStatementsOnASingleLine: true
< AllowShortLoopsOnASingleLine: true
---
> AllowShortIfStatementsOnASingleLine: false
> AllowShortLoopsOnASingleLine: false
37c38
< BreakBeforeTernaryOperators: true
---
> BreakBeforeTernaryOperators: false

Change-Id: I4ded7e36fb8bd5407cfba6d1c4f86e0bec620c0c
2016-10-17 15:41:56 -07:00
Frank Galligan
fc5f88d3d1 Fix temp files being left on system.
The webm temp files for testing and mkvmuxer_sample were not being
deleted.

BUG=https://bugs.chromium.org/p/webm/issues/detail?id=1314

Change-Id: I5d402de4b434965185e0fe73f2efd5f4dad8c6d6
2016-10-15 20:54:57 -07:00
Frank Galligan
c04a134986 Add support for overriding PixelWidth and PixelHeight.
Change-Id: I226f6bb6be99e71373fcbd8ec9b9d556064305e4
2016-10-15 18:19:19 -07:00
Frank Galligan
c0160e0ab5 Add support to explicitly set segment duration.
Adds a flag to sample muxer to copy input file's duration.

BUG=https://bugs.chromium.org/p/webm/issues/detail?id=1100

Change-Id: I9138f0301fa5c9f467c802d75e6ba32db156ae4f
2016-10-14 17:20:20 -07:00
Frank Galligan
02bc809f9d Add support to estimate file duration.
The code will estimate the file duration if the last block duration is
0. This is not totally correct, but better then what we currently have.

BUG=https://bugs.chromium.org/p/webm/issues/detail?id=1100

Change-Id: I8f81df0bd592e6f7b1925fa2637a2e09cf182742
2016-10-14 14:35:30 -07:00
Frank Galligan
c97e3e7d60 Add support to output sub-sample encryption information.
See http://wiki.webmproject.org/encryption/webm-subsample-encryption
for the format.

Change-Id: Ia5d6f3566b92c46911704108d3e86cd0fac9ee34
2016-10-13 09:04:52 -07:00
James Zern
26f434423f MakeUID: quiet unused param warning in Android builds
Change-Id: Id389af1d92184009c511ff641e86ac27c6767567
2016-09-28 18:51:03 -07:00
Frank Galligan
d6af52a1e6 Change check to fix compile error.
Change-Id: I01490cca4a0b6ae51b20117738a723b8c9788919
2016-09-15 15:33:23 -07:00
Michael Bradshaw
17200208c5 webm_parser: Add Mesh value for ProjectionType
Change-Id: I0e2be134cfefdb62edc54288720523646d01479a
2016-09-13 18:16:54 -07:00
Michael Bradshaw
78f2c5ab78 webm_parser: Use ./ prefix for includes
Fixes a lint presubmit check.

Change-Id: If06a7b11c18742dfe659136736082945a4853b3e
2016-09-08 15:42:22 -07:00
Michael Bradshaw
da62f659e4 webm_parser: Remove webm/ prefix from public includes
Using a webm/ prefix requires clients to add the webm_parser/include
path to their header search paths. This is inconvenient and an
unnecessary restriction.

Change-Id: If73a4433ad42f326a544766beca5f05710f52243
2016-09-07 16:57:44 -07:00
Michael Bradshaw
e15e8f2cc7 webm_parser: Update README build instructions
Change-Id: Iade055ff076b107ac1665493dad18e812025c31f
2016-09-01 15:52:18 -07:00
Tom Finegan
5023f2b5ca mkvmuxer: Fix Colour::Valid()
Ignore Colour::kValueNotPresent and allow writing of partial
Colour elements, and add a test confirming this works.

Change-Id: I77e6bd0d92cadc46142af92de2f9f474006dceb7
2016-09-01 11:56:03 -07:00
Tom Finegan
cf1620444f mkvmuxer_tests: Actually test cue points in the cue point test.
Instead of blindly doing a file compare and hoping that we're not
in a garbage in garbage out situation.

Change-Id: Ie2f278e09ad67b3e8f40e602fcdd5c9ffb5e1b7d
2016-08-31 21:18:30 -07:00
Tom Finegan
93e9fb35f9 Validate Colour element values.
webm:1284

Change-Id: Idc9fc2eee41e7ab445d90366c5ee3e8ca2509c81
2016-08-31 21:18:24 -07:00
Tom Finegan
8036925b43 mkvparser_tests: Add Projection element test.
Change-Id: Ib57449f409548b23ae1d788ca07dc19ba21e7763
2016-08-31 10:00:05 -07:00
Tom Finegan
f52d38cc5c mkvparser_tests: Add Colour element test.
Change-Id: Ifc0c9db863a0ebe17dbab0e94b82b6a04dd64926
2016-08-31 10:00:04 -07:00
Tom Finegan
826436a42f mkvparser: minor SeekHead::Entry clean up.
- Store actual element ID in SeekHead::Entry id field (instead
  of a decoded EBML int, which is completely _wrong_).
- Add a SeekHead::Entry constructor so we get initialized values
  in SeekHead::Entry's when parsing an Entry fails.

Change-Id: I152fae54628cb84918917139dba0cd0b42a44a57
2016-08-31 10:00:04 -07:00
Tom Finegan
24fb44aa1a mkvmuxer_tests: Add Projection element test.
Change-Id: I9a1e56d0846f43851ed0430ec52e2d7b816661fc
2016-08-31 10:00:04 -07:00
Tom Finegan
1e0a8eaa3c mkvmuxer_tests: Add Colour element test.
Change-Id: I5348930fb74d43f3fc4e1815d13a525bda70f4a0
2016-08-31 10:00:02 -07:00
Tom Finegan
027861614c mkvmuxer: Colour accessors/mutators.
Make data members of Colour and children private, and add
accessors and mutators for the changes members.

Change-Id: I203f6b4e8047cd4dae5c1b662649b535e05148fd
2016-08-30 18:13:51 -07:00
Tom Finegan
ce52f6e31d Merge "Add mkvparser wrapper functions." 2016-08-30 17:23:14 +00:00
Tom Finegan
6e5cbc09c0 Merge "webm_info: Add Projection element support." 2016-08-30 17:22:45 +00:00
Tom Finegan
0a039cb851 Merge "mkvmuxer_sample: Add support for Projection element." 2016-08-30 17:22:29 +00:00
Tom Finegan
149e8e997c Merge "mkvparser_sample: Add support for Projection element." 2016-08-30 17:21:37 +00:00
Tom Finegan
43f40c453d Merge "mkvparser: Add Projection element support." 2016-08-30 17:21:28 +00:00
Tom Finegan
0c9a19e20b Merge "mkvmuxer: Add Projection element support." 2016-08-30 17:21:17 +00:00
Michael Bradshaw
ff667d5fb4 Merge "Add support for the Projection element" 2016-08-30 16:49:37 +00:00
Tom Finegan
2346f8fafa Add mkvparser wrapper functions.
Add a couple mkvparser wrapper functions for testing mkvmuxer
output. Also expose HasCuePoints() via test_util.h for use
in cue point related tests.

Change-Id: I77321840926f41b60b6ceac65a1e3cfd79b7d2c2
2016-08-29 14:51:28 -07:00
Tom Finegan
54d6b6b60e webm_info: Add Projection element support.
Part of the Spherical Video V2 draft specification:
https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md

Change-Id: If37a7e3ede452a2545f613b50cd3cedd5dd64f09
2016-08-29 14:51:28 -07:00
Tom Finegan
65fee06599 mkvmuxer_sample: Add support for Projection element.
Part of the Spherical Video V2 draft specification:
https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md

Change-Id: If8cc7a102933ca7fe81990919dbabe7db97812f8
2016-08-29 14:51:25 -07:00
Tom Finegan
9a3f2b5762 mkvparser_sample: Add support for Projection element.
Part of the Spherical Video V2 draft specification:
https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md

Change-Id: I06d8e55d197fcf106b91d8d795ef85163ef5c2d5
2016-08-29 14:29:30 -07:00
Tom Finegan
41e814a008 mkvparser: Add Projection element support.
Part of the Spherical Video V2 draft specification:
https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md

Change-Id: I431349898b4018189cc58ce2cd67158ffb4c7f80
2016-08-29 14:29:30 -07:00
Tom Finegan
483a0ff800 mkvmuxer: Add Projection element support.
Part of the Spherical Video V2 draft specification:
https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md

Change-Id: Ia935ba975a0f01c1fb2919325ab7f70254c2ed10
2016-08-29 14:29:25 -07:00
Michael Bradshaw
676a7135d1 Add support for the Projection element
It's a part of the Google Spatial Media V2 spec:
https://github.com/google/spatial-media/blob/master/docs/spherical-video-v2-rfc.md

Change-Id: I52f05e34b19239af09774da2f88eb584a0bfa628
2016-08-29 13:15:07 -07:00
Tom Finegan
725f36207e mkvmuxer: Fix memory leak when Colour is set multiple times.
Change-Id: I5650ca1116a5ae678b11ac5f6a8abf1590bc9e3f
2016-08-26 21:08:30 -07:00
Tom Finegan
fa182de6e4 mkvparser_sample: Add output of audio track codec private size.
Change-Id: Ie0a2a379cd4e68ae751e514b3d3b2025c254500b
2016-08-26 21:08:29 -07:00
Tom Finegan
4aa5338ba5 Merge "mkvparser_tests: Add invalid BlockGroup test." 2016-08-26 22:10:03 +00:00
Tom Finegan
8f521f2192 mkvparser_tests: Add invalid BlockGroup test.
Change-Id: I2b24859a92d2beb5558c2afa817237c1f78f644d
2016-08-25 13:18:19 -07:00
Michael Bradshaw
dae3d48a6f Merge "Remove docs saying binary elements default to 0" 2016-08-25 18:36:29 +00:00
Michael Bradshaw
39137d7385 Remove docs saying binary elements default to 0
They don't have a real default, and certainly not an integer value of 0.

Change-Id: I839291b9960315241068f99a0926fca3ca27ac18
2016-08-25 11:19:52 -07:00
Tom Finegan
2349904020 Merge "Fix legacy Makefile." 2016-08-25 17:52:16 +00:00
Michael Bradshaw
16e5d2a369 Merge "Do not skip over unknown elements at the root level" 2016-08-25 17:43:34 +00:00
Michael Bradshaw
80685d3865 Do not skip over unknown elements at the root level
OnUnknownElement() should be called to handle them.

Change-Id: Iebd99631f094e95d0c3e75952930962e15826bac
2016-08-24 17:37:03 -07:00
Tom Finegan
c1475044b4 Fix legacy Makefile.
- Replace definition of EXES var (fixes all target building
  nothing).
- Update mkvmuxer/mkvmuxer sample target dependencies and
  exe names.

Change-Id: I2951e0b60ae8dc18b2a7cae28fa28624967df987
2016-08-24 12:21:56 -07:00
Tom Finegan
58711e8c3e mkvparser_sample: Fix version info string.
Change-Id: I87dfe753358aede2eb5219cfef7456151cb3a7e7
2016-08-24 12:03:08 -07:00
Tom Finegan
837746f4d2 mkvparser_tests: Add invalid block test.
Add test that confirms expected failure when a block
that ends beyond the current cluster is encountered.

Change-Id: I27abcab6d00b78c14b7ca00f51c97e43c5cdd34c
2016-08-23 17:55:52 -07:00
Tom Finegan
207cd80a86 Disambiguate sample sources and targets.
sample => mkvparser_sample
sample_muxer => mkvmuxer_sample

Change-Id: Iba6a1276da9c1bb4a46fc5c4521392f89f08a59e
2016-08-23 17:55:52 -07:00
Tom Finegan
a112d71cd0 mkvparser_tests: Refactor invalid file loading code.
Combine duped loading code into one method.

Change-Id: I3c4f9b7003f032a04b734f452f3c684d1af8e841
2016-08-23 17:55:49 -07:00
Tom Finegan
5dea33eacc Disambiguate test source and target names.
Rename source files and targets to better reflect what is
actually being tested.

muxer_tests => mkvmuxer_tests
parser_tests => mkvparser_tests

Change-Id: I921901f37d269f294b96ba20732b31c27f81945b
2016-08-23 10:29:30 -07:00
Tom Finegan
125049eecd parser_tests: Add another truncated chapter string test.
Causes mkvparser to fail in a slightly different way.

Change-Id: Id60fd43e6d0ef1871842367d19db52f60a8721cc
2016-08-19 12:44:43 -07:00
Tom Finegan
1de8d4cb4f parser_tests: Add truncated chapter string test.
Change-Id: I1714fbfea5bab61cca61cd32a0a0d30315ed56fc
2016-08-19 12:13:14 -07:00
Tom Finegan
ff8c2b6af7 parser_tests: Move cue validation to test_util.
And tidy it up a bit.

Change-Id: I68e7f16ad2aa922fdb064802e8986a6955364c32
2016-08-19 11:57:08 -07:00
Tom Finegan
4b0690faa2 parser_tests: Add invalid lacing test.
Also fixes leak this test exposed in mkvparser::Cluster.

Change-Id: I06ae11b72bc89219b6b2b407b4cc215982e3ae65
2016-08-19 11:57:05 -07:00
Tom Finegan
64ae831047 Merge "mkvmuxer: Set default doc type version to 4." 2016-08-12 21:59:33 +00:00
Tom Finegan
a351196dbb Merge "webm_parser: Reference more files in CMakeLists.txt." 2016-08-11 21:52:39 +00:00
Tom Finegan
9828e39874 mkvmuxer: Set default doc type version to 4.
mkvmuxer can write matroska v4 elements in all modes, but does
not always confirm that the doc type is high enough for all
elements written. The main culprits are Colour and its
children. Avoid problems by using 4 as the default version.
This avoids problems in all cases but those where users who
know what they are doing have written the EBML header manually.

Update the test files because the new default causes the file
compare abuse in the muxer tests to fail.

Update expected doc type version in the parsing tests.

BUG=webm:1201

Change-Id: I4c69000af4c1d5efe66315c17f3953344ef04993
2016-08-11 14:20:53 -07:00
Tom Finegan
5495a59d38 webm_parser: Reference more files in CMakeLists.txt.
Some includes were missed in the first pass when webm_parser
was added to CMakeLists.txt. Add the missing includes from
webm_parser/include/webm.

Change-Id: I193debe8018155ff9f0ab1d1326330069333948e
2016-08-11 08:48:45 -07:00
Tom Finegan
0c0ecd0f24 vpxpes_parser: Add start code emulation prevention support.
Remove bytes inserted to avoid start code emulation. Operates on:
- PES optional header
- BCMV header
- payloads.

Transforms the following byte sequences as noted (left converts to
right):
  0x00 0x00 0x03 0x01  =>  0x00 0x00 0x01
  0x00 0x00 0x03 0x03  =>  0x00 0x00 0x03

Change-Id: I09ae2d5bf03dfc1ade785ee89a773509eca8330c
2016-08-11 08:45:31 -07:00
Tom Finegan
639a4bc3b1 webm2pes: Remove debug printfs().
Change-Id: I13ba6590c63e7fef14efee812095ac704ef8b69e
2016-08-10 14:56:33 -07:00
Tom Finegan
9a51102cb5 webm2pes: fflush() in the correct conversion function.
Change-Id: I79db8b24178d4e7ba205995525b74a09efef8a04
2016-08-10 14:56:33 -07:00
Tom Finegan
dc7f15559f webm2pes: Track total bytes written.
Change-Id: I78807280cbd05f642215c83d5db4d04837c06438
2016-08-10 14:56:33 -07:00
Tom Finegan
d518128266 webm_parser: Enable usage of werror.
Mass warning clean up. Mainly:
- Explicit casts of numeric literals to avoid signed/unsigned compare
  warnings.
- Commenting out of unused function arg names.

Change-Id: I0e70393a5743ae984035d43712c724d4ccd12f9d
2016-08-10 08:56:57 -07:00
Tom Finegan
e1fe7627c8 webm2pes: Add test for mux/demux of large input.
Change-Id: I253aa49aa3757682dbba83bd9ba6dd1e93d7ccce
2016-08-08 11:15:29 -07:00
Tom Finegan
1b24a792e3 vpxpes_parser: Read and store PTS when present.
Change-Id: I11acb45b26eeea6f5945c04bb447937ba2ffca9f
2016-08-08 11:15:23 -07:00
Tom Finegan
6cf0a0f400 vpxpes_parser: Store frame payloads.
libwebm_util:
- Add 90khz -> nanosecond conversion.

vpxpes_parser:
- Get rid of VpxPesParser::VpxFrame and use VideoFrame.
- Store/Accumulate (when neccessary) PES payloads in
  VideoFrames.
- Change type of size constants from int to size_t.
- Return offset accounting for origin from FindStartCode().
- Check all PTS marker bits (instead of checking the second
  marker twice).

video_frame:
- Add nanosecond_pts mutator.

webm2pes:
- Write DTS/PTS presence flag correctly when PTS is not
  present.

Change-Id: I10f16cd03bb3a51205a25331527ddceb3769ba03
2016-08-08 11:14:03 -07:00
Tom Finegan
25d26028c1 webm_parser: Convert style to match the rest of libwebm
Remove webm_parser/clang-format-style.
Run clang-format -style=file -i for each source file.

Change-Id: Ieaf44bd323375cbcfec67014e94b7742d6bda14a
2016-07-27 14:31:28 -07:00
Tom Finegan
24be76dcb2 webm2pes: Replace VpxFrame with VideoFrame.
VideoFrame was created in order to get rid of the two
slightly different VpxFrame implementations. This patch
gets rid of Webm2Pes's version.

Change-Id: I5af29d5ca717121ee7ab30f28e42d2a43ea5abb0
2016-07-22 15:07:42 -07:00
Tom Finegan
b451c3ba96 Add a basic video frame storage class.
Includes simple tests.

Change-Id: I52276686d6c2bc7b62d260af37affe78aa4dcf50
2016-07-22 15:07:33 -07:00
Tom Finegan
05c90ebccc libwebm_util: Clarify error text in superframe parser.
Change-Id: Icb478d58306bc5e501df9585ece35c9747dd640d
2016-07-22 11:34:18 -07:00
Tom Finegan
e6415af941 webm2pes: Make WritePesPacket() a public method.
WritePesPacket() now takes a VpxFrame as input and a
PacketDataBuffer* as an output  parameter, and avoids
using members entirely. This facilitates deeper testing
of Webm2Pes without requiring friendship with test
classes and methods.

Change-Id: I076db8900cc1a5c864b54f5fe3403fb05b4bd835
2016-07-20 17:36:46 -07:00
Tom Finegan
8f840ddaa3 webm2pes: Move frame read out of PES packet write method.
Makes writing tests easier by allowing caller to pass data
for packetizing directly into the method.

Change-Id: I553fa8c1636041c4a5ff043862918a5cdc9163ba
2016-07-20 14:00:36 -07:00
Tom Finegan
448af971d2 webm2pes: Restore frame fragmentation support.
Cap packet payload at 32 kB. Update test to expect non-zero
packet length.

Change-Id: Ibb68a4ef8d32c049c492ae546c631ef6376e3ffd
2016-07-18 14:32:02 -07:00
Tom Finegan
f8bb7149f5 cmake: Integrate new parsing API and tests.
Change-Id: I11e32bfffda12fa910c06bf7b8e3a0efbccf6054
2016-07-14 11:11:59 -07:00
Michael Bradshaw
cb8ce0b4b5 Add a new incremental parsing API
Change-Id: I6b921766836d58df0281fb23b2add3f62a478e14
2016-06-15 12:39:58 -07:00
Tom Finegan
900d322cc8 vpxpes_parser/webm2pes: BCMV and PTS fixes.
- Write BCMV length value big endian and include BCMV header
  size.
- Write PTS bits big endian.

Change-Id: I8cd72c233c21f5909438f5a3bb817e9477bdfcfb
2016-06-02 17:05:09 -07:00
Tom Finegan
4b735452bb webm2pes: Add start code emulation prevention.
- Make start codes reliable for VPx in PES.
- Stop setting the PES size field and stop splitting packets when
  larger than UINT16_MAX (always set 0; rely on start codes to find
  packet boundaries).

Change-Id: I402e91c26562e930f61543ca59223b83cc92be29
2016-06-02 17:05:07 -07:00
Frank Galligan
82903f36fa Add column tiles and frame parallel to webm_info
BUG=https://bugs.chromium.org/p/webm/issues/detail?id=1227

Change-Id: I23b1611a91074bfa0cff3b788baeff71bc68d034
2016-05-17 09:00:41 -07:00
Vignesh Venkatasubramanian
5d91edf9f1 style_clean_up: Remove unnecessary parentheses
Change-Id: Ie3645319fa4d5a1fd254b4511a60ef6f6036afe5
2016-05-13 10:41:16 -07:00
hui su
a95aa4b294 vp9_level_stats: correct total_uncompressed_bits_ calculation
Only consider display frames.

Change-Id: I9061ad90775f0467a661b0ac5d11dc22e477a7c3
2016-05-06 15:37:09 -07:00
Tom Finegan
f46566f19a mkvreader: Fix shorten-64-to-32 warning in 32 bit builds.
BUG=https://bugs.chromium.org/p/webm/issues/detail?id=1207

Change-Id: Ie1c97a314fefdf14dce455da16f5a29218ba4cf8
2016-05-06 11:40:48 -07:00
Tom Finegan
76630ca4a3 mkvwriter: Fix shorten-64-to-32 warning in 32 bit builds.
BUG=https://bugs.chromium.org/p/webm/issues/detail?id=1207

Change-Id: I2dc1ce59ebf8051c9661b919813d5ab7cb115da0
2016-05-06 11:40:44 -07:00
Tom Finegan
a8ffbd4ed2 webm2pes: Fix format specifier warnings.
BUG=https://bugs.chromium.org/p/webm/issues/detail?id=1207

Change-Id: If60866f8e60969bc6cbaef8eee72a805270bf65d
2016-05-06 11:40:38 -07:00
Frank Galligan
21015480f6 Merge "Add MaxLumaSampleRate grace percent to stats." 2016-05-02 22:00:22 +00:00
Frank Galligan
faf89d4ed1 Add MaxLumaSampleRate grace percent to stats.
BUG=https://bugs.chromium.org/p/webm/issues/detail?id=1206

Change-Id: I29a956871bd5aa0c7b493601ed23b44a08414d32
2016-04-30 16:59:42 -07:00
Frank Galligan
d31e6c970d Fix profile 2 in vp9_header_parser.
BUG=https://bugs.chromium.org/p/webm/issues/detail?id=1208

Change-Id: Ie31adef15eac965e3fb587825f63ff320c1d59fe
2016-04-29 17:11:29 -07:00
Frank Galligan
4fc66dab83 Merge "Add flag to estimate last frame's duration to stats." 2016-04-29 22:30:12 +00:00
Frank Galligan
bd3ab3abe6 Add flag to estimate last frame's duration to stats.
BUG=https://bugs.chromium.org/p/webm/issues/detail?id=1204

Change-Id: Ie73e2981951f9eb6140bdfb0a6839320e009b7fe
2016-04-29 14:19:58 -07:00
Vignesh Venkatasubramanian
c89b968ce5 Merge "Fix lint issue in hdr_util.h" 2016-04-29 19:31:52 +00:00
Vignesh Venkatasubramanian
db5693d96b Merge "Add test for Cluster memory leak" 2016-04-29 19:31:40 +00:00
Vignesh Venkatasubramanian
c182ed97d1 Fix lint issue in hdr_util.h
Change-Id: Iba19ad153f9187c3942d406e41da04703f7dd5c7
2016-04-29 11:47:04 -07:00
Vignesh Venkatasubramanian
cc62ecd23f Add test for Cluster memory leak
Tests the scenario described in this CL:
https://chromium-review.googlesource.com/#/c/341251/

Change-Id: I4d732eebc11140691ed516321cf490905991720b
2016-04-29 11:42:36 -07:00
Frank Galligan
196708a95f Change MaxLumaSampleRate to be based on frame resolution.
MaxLumaSampleRate generation code now takes into account the frame
resolution of every frame.

BUG=https://bugs.chromium.org/p/webm/issues/detail?id=1203

Change-Id: I666fa2f21971ff4fb80219ef29dee3254cbb370c
2016-04-29 08:15:37 -07:00
Vignesh Venkatasubramanian
26d673e737 Merge "mkvmuxer: Fix leak when a Cluster isn't finalized" 2016-04-29 02:17:33 +00:00
Frank Galligan
eacb314525 Merge "Add parsing support for new features in CodecPrivate." 2016-04-29 00:17:28 +00:00
Vignesh Venkatasubramanian
cbd676bb66 mkvmuxer: Fix leak when a Cluster isn't finalized
There's a leak in the following scenario:
  * AccurateClusterDuration is set to true.
  * Add a few frames.
  * An error is encountered while adding a frame and the
    application bails without calling Cluster::Finalize
  * All the frames we queues in QueueOrWriteFrames now leak.

This patch fixes this scenario by delete'ing any left over frames
in the Cluster's destructor.

Change-Id: I104f6814db18a86fae9877decfe6cc75b8937fcb
2016-04-28 12:30:29 -07:00
Tom Finegan
9a235e0bc9 mkvmuxer: Set doctype to matroska when muxing non-WebM codecs.
Also, add some constants for WebVTT codec ID strings so they
won't cause doctype to incorrectly change to matroska.

Change-Id: I4740a3e45b28a22e462601b9ce051aa01817dace
2016-04-28 08:44:14 -07:00
Frank Galligan
47f2843e79 Add parsing support for new features in CodecPrivate.
Adds support for parsing bit depth and chroma subsampling features.

BUG=https://bugs.chromium.org/p/webm/issues/detail?id=1198

Change-Id: I8d11829f5d43a518cbe0e5c0bdd4fd37db7b6266
2016-04-27 09:27:24 -07:00
Frank Galligan
e3c9576716 Add VP9 level output to webm_info.
Removed building webm_info from Makefile.unix as it now requires c++11.

BUG=https://bugs.chromium.org/p/webm/issues/detail?id=1188

Change-Id: Ia142f0c3cd580f397449d2ffa8788f78fb7faff0
2016-04-26 22:16:31 -07:00
Frank Galligan
de3234a87f Merge "Add class to gather VP9 level stats." 2016-04-26 15:29:49 +00:00
Tom Finegan
5cf549f582 cmake: Log compiler flag at check time.
Output the flag being checked before checking the flag to make it easier
to determine exactly which check failed.

Change-Id: I692f5287f985acb4a3061dd54f7c5a8729def83b
2016-04-21 16:56:12 -07:00
Frank Galligan
bbaaf2da8d Add class to gather VP9 level stats.
See http://www.webmproject.org/vp9/profiles/ for more information
on VP9 levels.

BUG=https://bugs.chromium.org/p/webm/issues/detail?id=1188

Change-Id: I91448069bbd4740106a159014db6935365af75ca
2016-04-21 13:02:25 -07:00
Frank Galligan
8bb68c2b3e Add file to parse data from VP9 frames.
This class will parse and collect some data from VP9 frame
headers.

BUG=https://bugs.chromium.org/p/webm/issues/detail?id=1188

Change-Id: Ie19e0f4a2f7e89d0378a66ce2e8e939250ddc383
2016-04-18 12:21:58 -07:00
Frank Galligan
a004fefc56 Merge "Add support for setting VP9 profile and level to sample_muxer." 2016-04-18 19:20:17 +00:00
Frank Galligan
58e33b3329 Merge "Add support to parse VP9 profile." 2016-04-18 19:20:04 +00:00
Frank Galligan
296429a7dc Add support to parse VP9 profile.
This is the VP9 profile contained in the CodecPrivate data.

Change-Id: If5fd5667bfc86ff596354457539da363367128db
2016-04-18 12:15:59 -07:00
Frank Galligan
df3412f68d Add support for setting VP9 profile and level to sample_muxer.
BUG=https://bugs.chromium.org/p/webm/issues/detail?id=1179

Change-Id: I20ffc213764c3c1c35563178b6e8e1e0031760b6
2016-04-18 12:13:45 -07:00
Vignesh Venkatasubramanian
87832d487a mkvmuxer: Fix Segment::Finalize in kLive mode
Do not call Cluster::Finalize in kLive mode unless
accurate_cluster_duration_ is set.

Change-Id: Id2627b5df9eaee065e12d08b494ee02ae0a33564
2016-04-15 20:32:19 -07:00
Tom Finegan
6df3e5630e mkvmuxerutil.hpp: Add using directives for overloaded size utils.
Some downstream code using the EBML element size requires that
EbmlElementSize and EbmlMasterElementSize are accessible in the global
namespace.

Change-Id: I9d110b683e434c90f96ae7b35b35e79eb6a2335f
2016-04-14 17:16:31 -07:00
Tom Finegan
ec479287ff mkvmuxerutil: Revert to using mkvmuxertypes.
- The direct change to stdint.h types causes too much downstream
  churn. Need an intermediate step or a wrapper because quite a
  bit of user code explicitly casts args passed to mkvmuxerutil
  functions to types defined in mkvmuxertypes.
- Update call sites in mkvmuxer to avoid ambiguity errors.

Change-Id: I018445b3d8ab1da776ecdb19a290ac00af63c2cf
2016-04-14 12:58:38 -07:00
Frank Galligan
7d674468bd Merge "Add support to output Colour elements to webm_info." 2016-04-13 16:15:30 +00:00
Frank Galligan
a1dc4f2f22 Fix parsing of VP9 level.
The VP9 level is contained in the CodecPrivate data.

Change-Id: I65475363ee230b422a8cdce8172f6262cb3329e7
2016-04-12 23:00:03 -07:00
Frank Galligan
4e3d037374 Add support to output Colour elements to webm_info.
BUG=https://bugs.chromium.org/p/webm/issues/detail?id=1178

Change-Id: I50825e320a0c93dd565bf89c9478feb434277ddb
2016-04-12 21:46:00 -07:00
Tom Finegan
836591f4f5 Merge "Add TEST_TMPDIR environment variable" 2016-04-13 00:26:58 +00:00
Tom Finegan
d3656fdb8b muxer_tests: ignore iwyu re gtest-message.h
Just pull it in via gtest.h.

Change-Id: If04d569a74da925f8544858861057af497f3f2bf
2016-04-12 14:49:21 -07:00
Tom Finegan
e76dd5e3e2 Fix file name in mkvmuxertypes shim.
Change-Id: I78d3784139727b65a47aaf1eb987d8b9ab14de37
2016-04-12 13:27:57 -07:00
Tom Finegan
1be5889a6d Add temporary include shims at old file locations.
Helps ease the downstream transition to the new libwebm layout.

BUG=28069412

Change-Id: I0d4182e22a10fecdd5982b8aceba687dea9529d8
2016-04-11 23:25:20 +00:00
Tom Finegan
32d5ac4941 mkvmuxerutil: Fix MSVC build.
Avoid a couple implicit casts.

Change-Id: I3299272769d15c08c733ced1b0f95bdf75848e6f
2016-04-08 21:46:31 -07:00
Tom Finegan
6397597194 vpxpes_parser: Fix MSVC build.
Replace implicit cast with explicit cast.

Change-Id: I6e8948e46b7589af334eaea3b41e0bcb808b7825
2016-04-08 21:23:12 -07:00
Tom Finegan
784b6fe4fe mkvmuxer: Revert changes to IMkvWriter types.
- Restore integer typedefs in mkvmuxertypes.h.
- Revert integer type changes in IMkvWriter declaration.
- Revert integer type changes in mkvwriter.{cc,h}

Change-Id: I3e9f8a3d079f485a3ea051f7477c803f9c9087e4
2016-04-08 10:50:57 -07:00
Tom Finegan
030518edd3 webm_info: Fix implicit conversion warnings.
Fix warnings exposed by addition of -Wshorten-64-to-32 to compiler
flags.

Change-Id: I56f10e6c9af8c4fafebe8fbe00739f775cf31492
2016-04-08 10:45:33 -07:00
Tom Finegan
46d5dee461 sample_muxer: Fix implicit conversion warnings.
Fix warnings exposed by addition of -Wshorten-64-32 compiler flag.

Change-Id: I17fe8439a88f68fc4b8f7a6774132570dfe251da
2016-04-08 10:45:33 -07:00
Tom Finegan
22b0845686 webmts: Fix implicit conversion warnings.
Fix warnings exposed by addition of -Wshorten-64-32 compiler flag
in webmts sources.

Change-Id: I3104e7be2bf991d7e108b652857ecca8e82c5ef9
2016-04-08 10:44:35 -07:00
Tom Finegan
ef464c2a95 mkvparser: Fix implicit conversion warnings.
Fix warnings exposed by addition of compiler flag
-Wshorten-64-to-32.

Change-Id: I9adcfa97babbda1a5d94fe06ec84eab69eb8d842
2016-04-08 09:23:35 -07:00
James Zern
0e9767e29a Merge "rename mingw64_toolchain.cmake to mingw-w64_toolchain" 2016-04-08 05:33:15 +00:00
Tom Finegan
f47cbd50e9 cmake: Move cxx flag testing/setup into its own file.
- Move CXX flags stuff into build/cxx_flags.cmake.
- include CMake modules where they're used.
- Add ENABLE_WERROR flag-- enables warnings as errors.
- Add -Wshorten-64-to-32 and -Wnarrowing to CXX flags.

Change-Id: I5d93a39a3eff6ae81f9e094927b8f0cb9f36bbb0
2016-04-07 14:49:26 -07:00
Vignesh Venkatasubramanian
039df94e87 Add TEST_TMPDIR environment variable
Honor TEST_TMPDIR environment variable for creating temporary test
files in non-windows platforms. This helps in environments where
we cannot create a temporary file in the current directory.

Change-Id: I39e0a19580635d752171e0573dd21ec838cb81a4
2016-04-07 10:55:28 -07:00
James Zern
87443a6b8f rename mingw64_toolchain.cmake to mingw-w64_toolchain
Change-Id: I9101fd87d2eb5ef56c4441b4c46f35e85aff04d8
2016-04-07 10:46:24 -07:00
Tom Finegan
2aee04fb23 msvc_runtime.cmake: Check for MSVC, not WIN32.
- The flag change here is supposed to target only MSVC builds,
  and not all Windows builds.
- Style tweak to match other CMake files.

Change-Id: I664705e13d810e2d41422eae655b5a68ff244308
2016-04-07 10:36:07 -07:00
Vignesh Venkatasubramanian
eb50da8e38 Option to write timecode using fixed # of bytes
Add an option to write the cluster timecode using exactly 8 bytes
irrespective of the actual number of bytes required to write it as
an ebml integer.

This could be useful for players that want to rewrite the timecode
in-place (e.g. live streaming).

Change-Id: I1a049251f00ab65591d71e169129f5145a8c8863
2016-04-06 15:09:19 -07:00
Tom Finegan
c1991fea81 mkvmuxer: Add missing Segment member initializer.
Change-Id: If8d6e12de3671e864ecb6c5ca0873a1fc69c3820
Segment::accurate_cluster_duration_ init missing from ctor.
2016-04-06 13:37:07 -07:00
Tom Finegan
10aed96a9c Android.mk: Make libwebm easier to build downstream.
- Explicitly add the libwebm path as an include directory, and export
  it to ensure the include path propagates to other builds depending
  on libwebm.
- Disable clang/gcc warning extern-c-compat; it's triggered in Android builds
  by built-in includes.

Change-Id: I631f5a6f3b50a73519ae436033257de7e25afb16
2016-04-06 13:36:19 -07:00
Tom Finegan
5c50e310e7 Add support for parsing VPx track codec private data.
Currently only the VP9 profile level is supported.

http://www.webmproject.org/vp9/profiles/

Change-Id: Iff7238e104621b53fdd51a67d752bd72b2dbbacb
2016-04-04 11:16:33 -07:00
Tom Finegan
4cbdbf1978 Fix Android build.
- Missing STDC_{CONSTANT,FORMAT,LIMIT}_MACROS.
- Missed an int32 during conversion to stdint.h types.

BUG=https://bugs.chromium.org/p/webm/issues/detail?id=1171

Change-Id: I744449dc5fef53827f0caa837a15aafe30d6e553
2016-04-04 11:16:22 -07:00
James Zern
bb48a3fc63 mkvmuxerutil: remove stray 'int32'
fixes Android compilation of this file

Change-Id: Ib469c750baf05837f6475487a6f03465e56a9013
2016-04-02 11:45:32 -07:00
Tom Finegan
a1cba3409a Support cross compile for windows via mingw64.
BUG=https://bugs.chromium.org/p/webm/issues/detail?id=1170

Change-Id: I8430600ceb610fbf1ecff34f0a2d2c1a57627692
2016-04-01 19:11:12 -04:00
Tom Finegan
596f5e0544 Add webm_info.
Migrated from the webm-tools repository with minor tweaks to
fix its build in the new location.

Last location/revision:
https://chromium.googlesource.com/webm/webm-tools
a7e97e8f0a913ddd97444392bb8816f44a4821a1

Change-Id: Icfad43d9fdd37fc413a6a28b57b370c97c7c28df
2016-04-01 12:07:38 -04:00
Tom Finegan
ccf75f67a0 msvc/muxer_tests: Silence integer conversion warnings.
Change-Id: Ic11a83968aa5a70ca364ebce97d465f74cda5eee
2016-03-31 10:43:10 -07:00
Tom Finegan
2ff2954fa9 msvc/webm2pes: Silence integer and floating point conversion warnings.
Change-Id: I5379b5a3896b316327f35ebfaa3b2fc8545f002b
2016-03-31 10:43:10 -07:00
Tom Finegan
1f2432397f msvc/hdr_util: Silence double to float conversion warnings.
- Use float instead of double for Colour children in mkvparser.
- Add casts where appropriate.

Change-Id: Ia0f7e4dc25536cd43bc5e9439c58770dc3d79bc5
2016-03-31 10:43:05 -07:00
Tom Finegan
074456386e msvc/vpxpes_parser: Silence integer conversion warning.
Change-Id: I968693578f5596ebef6f576765a19f8210db5f4a
2016-03-31 10:32:37 -07:00
Tom Finegan
59614b8fae msvc/libwebm_util: Fix floating point to int conversion warning.
Change-Id: I3f813df344989b0200a49215ab0562d896577425
2016-03-31 10:32:35 -07:00
Tom Finegan
6481c24a19 webvtt: Fix include in vttreader.
Change-Id: I270acebca3e38114362af4d682d5034fda942c84
2016-03-30 12:32:23 -07:00
Tom Finegan
e6ed0f4817 msvc/vpxpes2ts: Fix MSVC integer conversion warning.
Change-Id: Ia2613f160b76f664cbdfeb314026f056f4be2fcc
2016-03-30 12:32:22 -07:00
Tom Finegan
da6439685d cmake/msvc: Disable C4996 project wide.
MSVC C4996 triggers upon use of functions like fopen, and suggests
use of non-portable Microsoft replacements. Disable it project wide,
and remove the pragmas littered throughout the tree.

Change-Id: I8b890bbfd3cd7224c25350bd28f334facd8b7783
2016-03-30 12:32:22 -07:00
James Zern
6ef8264fcc Merge "mkvparser::BlockEntry: inline EOS()" 2016-03-30 00:30:11 +00:00
James Zern
3fa6aecb7f mkvparser::BlockEntry: inline EOS()
Change-Id: I1cd5ef4e438a285c733c9246411513f670c2c9c4
2016-03-29 16:55:42 -07:00
Tom Finegan
26306f9214 mkvmuxer: Remove unused Cluster ctor overload.
Remove Cluster ctor overload unintentionally added during a merge
because the default ctor is causing an uninit'd memory error in
valgrind.

BUG=https://bugs.chromium.org/p/webm/issues/detail?id=1161

Change-Id: I21b8110488bc6def0a3b5d07cbede37170087e6d
2016-03-29 14:32:43 -07:00
Tom Finegan
0d765974cd mkvmuxer: Fix build with GCC 5.3.
BUG=https://bugs.chromium.org/p/webm/issues/detail?id=1160

Change-Id: I7d8a0a7fa1aef2e459e54effd448186c850453be
2016-03-29 12:21:10 -07:00
Tom Finegan
0ba80bcbf4 mkvparser/sample: Minor clean up.
- Return EXIT_FAILURE/EXIT_SUCCESS from main().
- Fix usage.

Change-Id: Id22d9c5cff9c8e220b4d19c519bf35f8b69ed2df
2016-03-29 09:02:52 -07:00
Tom Finegan
2e0e906eac iosbuild.sh: Fix build.
Update the framework build script to support the new
layout of the libwebm repo.

Change-Id: I4852eb116b7a4b891e570cad3be830fc961ba2f8
2016-03-23 10:09:59 -07:00
James Zern
918440adaf Makefile.unix: allow CXXFLAGS to be easily overridden
separate out required flags allowing CXXFLAGS to append them

Change-Id: I2ecd68c7c153da5f17e3b53e1c8ae4e739c65f4c
2016-03-22 20:55:33 -07:00
Tom Finegan
4ff5785938 cmake: Add C++11 move ctor and member initializer tests.
Change-Id: I747a206db03fcb8f13265e0c56c86dd5a9f6eff8
2016-03-21 14:41:49 -07:00
Tom Finegan
402ef4dd4d cmake: remove argc and argv from C++11 test main fns.
Avoid failing feature tests because of potential unused variable
warnings.

Change-Id: Iaae3a86581ce7beefeaf6c2300c87064fc8d6d56
2016-03-21 14:41:49 -07:00
Tom Finegan
cbe5c40d12 Restore original namespaces for mkvmuxer and mkvparser.
Wrapping mkvmuxer and mkvparser in the libwebm namespace is no
longer necessary now that the tree reorganization is complete.
Put mkvmuxer and mkvparser namespaces back in the global
namespace to avoid unnecessary churn in downstream code.

Change-Id: I13a4fe0143d20bb2bb6038078c68636ff2af0c29
2016-03-21 14:41:49 -07:00
Tom Finegan
504e0f2d5b Mass file extension update.
- Use .cc and .h everywhere.
- Update includes/include guards.
- Remove extra makefile targets necessitated by previous mix
  of cpp/cc.

Change-Id: I7aad29152d4177937f8f42927c16c6572228c104
2016-03-21 14:41:47 -07:00
Tom Finegan
79cb9805c1 Android.mk: Update source file locations.
Change-Id: I92cdf3c5616edf0450bce85963f415e10c5cb21d
2016-03-21 14:41:24 -07:00
Tom Finegan
01db4c2d83 webmids: Move to common/ sub dir.
Change-Id: I87d0cbd78203a6680108e9e36588ff35e7ae8a4e
2016-03-21 14:41:24 -07:00
Tom Finegan
235ce59396 mkvparser: Explicitly reference internal sources in includes.
Change-Id: I09f2ab1e6fd4a41b242931e12cb4f147f8019247
2016-03-21 14:41:24 -07:00
Tom Finegan
f578419a01 mkvmuxer: Move sources to mkvmuxer/ sub dir.
Change-Id: I22dff1e2ece102c294081ab2ec8600fdb872922e
2016-03-21 14:41:19 -07:00
Tom Finegan
5f1065e4e2 webvtt: Organize and clean up webvtt support.
Move webvtt support code into webvtt sub dir, and update build/includes
as necessary.

Change-Id: I1c0891afd413e92d43ba54b61cc8dc694c0bff36
2016-03-21 12:41:47 -07:00
Tom Finegan
7abe8ace91 cmake: Add missing dumpvtt target.
Change-Id: Ie751a8bcf10d554dd2dad7171b27df22bf442d40
2016-03-21 12:41:47 -07:00
Tom Finegan
f2f87e20ed Makefile.unix: Tidy things up.
- Stop the abuse of OBJECTS$N (where N is just a magic number that's been
  incremented each time the line length crossed 80 cols).
- Put WebVTT objects in VTTOBJS
- Put executable objects in EXEOBJS
- Move symbol defs to $(DFLAGS)
- Add $(INCLUDES) to $(CXXFLAGS); stop using it in rules.

Change-Id: I140c8a779f9f42586b7179262690c86801163f89
2016-03-21 12:41:47 -07:00
Tom Finegan
12f6dc34b4 Use <stdint.h> types instead of custom typedefs.
Change-Id: Ia43b81649a14d0509aef2119be7a0ea9be955201
2016-03-21 12:41:45 -07:00
Vignesh Venkatasubramanian
0407360dcf mkvmuxer: Write last block in each Cluster with Duration
This helps browsers implementing Media Source Extensions (MSE) to
know the exact duration of a Cluster without relying on the next
Cluster.

Change-Id: Idd0422e432430c5702a4864740f89fc6d3c85189
2016-03-18 12:24:42 -07:00
Tom Finegan
008aa63d6a mkvparser: move to mkvparser sub dir.
Move mkvparser and mkvreader to mkvparser/.

Change-Id: I18c4575483f628344034d81b7d90d3aa86c163ff
2016-03-18 10:22:22 -07:00
Tom Finegan
e64bf75688 Namespace reorg: Make everything a child of libwebm.
(that is not already)
Some details:
- mkvmuxer and mkvparser wrapped by libwebm
- Matroska element constants moved from mkvmuxer to libwebm
- integer types moved from mkvmuxer to libwebm

Change-Id: Ic91e887e50adbc2d735bf6264534a5d01135df31
2016-03-18 10:22:16 -07:00
Tom Finegan
5fdb386183 cmake: move c++11 checks into build/cxx11_tests.cmake.
Change-Id: I300552a14412dc664e7e5f1a4d1a90466e82593d
2016-03-16 20:14:26 -07:00
Vignesh Venkatasubramanian
367248817e Copy reference block values in Frame::CopyFrom()
Change-Id: I6cde588e98326664227ea9db1dcd643845a60ca6
2016-03-16 15:03:33 -07:00
clang-format
91ca780522 reapply clang-format
Change-Id: Ic04e8429b07fe9b7dc15dc836d16ba9f30317ee2
2016-03-16 12:18:08 -07:00
Vignesh Venkatasubramanian
8d3421503f Merge "Clean up AddAudioTrack in muxer_tests" 2016-03-16 00:25:30 +00:00
Vignesh Venkatasubramanian
90861d4fb6 Clean up AddAudioTrack in muxer_tests
Moving AddAudioTrack into a separate function and keeping it
simple so that it can be re-used from other tests that might
require adding an audio track.

Change-Id: Ia60ed63ddbe617764596eb9c5a2bf96108c47cdd
2016-03-15 17:23:13 -07:00
Vignesh Venkatasubramanian
a9dfb3d3a3 Un-ignore webm files in testdata
Only ignore .webm files in the root directory of the repository.

Change-Id: Ic95e7013781f760b4947e4483f33472052724460
2016-03-15 16:19:44 -07:00
Tom Finegan
c5b76d8d11 Extract PES parser from WebM2Pes tests.
Change-Id: I6c81255635a65337bdb701119a3814801864469d
2016-03-11 14:12:57 -08:00
Tom Finegan
16524e8e3b cmake: Add include-what-you-use integration.
Change-Id: Ifcfd15e0b7b81c013116ad770985a3fe4911391a
2016-03-10 14:47:43 -08:00
Tom Finegan
7015af5b08 iwyu/vpxpes2ts: Update includes.
Include what you use analysis based include update.

Change-Id: I6e7b296886c477107f8d50a7ed02187d01df125c
2016-03-10 09:21:48 -08:00
Tom Finegan
c1d6a70204 iwyu/webm2pes: Update includes.
Include what you use analysis based include update.

Change-Id: Ib390c6a669d31ec298a4db407a50904576b99d91
2016-03-10 09:21:48 -08:00
Tom Finegan
110e79790b iwyu/libwebm_util: Update includes.
Include what you use analysis based include update.

Change-Id: I272351418ac19e66989ea7ba23b01561ff7a8ed4
2016-03-10 09:21:48 -08:00
Tom Finegan
44e31fb4d9 iwyu/webm2pes_tests: Update includes.
Include what you use analysis based include update.

Change-Id: Iaef395051e24654933c278f63965491091775773
2016-03-10 09:21:48 -08:00
Tom Finegan
d919f96171 iwyu/mkvwriter: Update includes.
Include what you use analysis based include update.

Change-Id: Ic3c0f943c3d9fc633d4b5b1f649f10ddf54692c7
2016-03-10 09:21:48 -08:00
Tom Finegan
75790e1e63 iwyu/mkvparser: Update includes.
Include what you use analysis based include update.

Change-Id: If117dad749c6854dd2023a64abef9ab3b163196b
2016-03-10 09:21:48 -08:00
Tom Finegan
5f673caf7a iwyu/webm2pes_main: Update includes.
Include what you use analysis based include update.

Change-Id: I7fc997acd0839d9543438fca01000ebb37a45dbb
2016-03-10 09:21:48 -08:00
Tom Finegan
747244af1d iwyu/vpxpes2ts_main: Update includes.
Include what you use analysis based include update.

Change-Id: Ifa09162b0a6783e353e9cd494143c5118e22200d
2016-03-10 09:21:48 -08:00
Tom Finegan
94c985f5ff iwyu/mkvmuxerutil: Update includes.
Include what you use analysis based include update.

Change-Id: I6cd977b2bbeee4a8ef960a074aed52db35db4d89
2016-03-10 09:21:48 -08:00
Tom Finegan
c365630718 iwyu/mkvmuxer: Update includes.
Include what you use analysis based include update.

Change-Id: I6edfaadf88ecbf52bfcb2de6e12716935e46bcd2
2016-03-10 09:21:48 -08:00
Tom Finegan
b15b8ef1a0 iwyu/file_util: Update includes.
Include what you use analysis based include update.

Change-Id: I1aafbf5d9781a04e4b05f8e63ee72c6070df7b2b
2016-03-10 09:21:48 -08:00
Tom Finegan
3dfba9576a iwyu/hdr_util: Update includes.
Include what you use analysis based include update.

Change-Id: Iaa744570fe3e8f9eddc0fdbd1528c0689a3c40cb
2016-03-10 09:21:46 -08:00
Tom Finegan
baba8b128d iwyu/vttdemux: Update includes.
Include what you use analysis based include update.

Change-Id: Id7b8b9113da70c378a9db904cac1701fc8ebd6d2
2016-03-10 09:21:19 -08:00
Tom Finegan
3212ec1223 iwyu/webvttparser: Update includes.
Include what you use analysis based include update.

Change-Id: Ia02c7d2af742cb1643d28d0acfa94e3324c8fa46
2016-03-10 09:21:19 -08:00
Tom Finegan
b6d8d9241a iwyu/sample_muxer_metadata: Update includes.
Include what you use analysis based include update.

Change-Id: Ib3fa6a5a3b6afadf56d52f7feb9264e18b454cd3
2016-03-10 09:21:18 -08:00
Tom Finegan
a9a1a01551 iwyu/sample_muxer: Update includes.
Include what you use analysis based include update.

Change-Id: I289bef3b5237940ef4f9b92168afca0765468e89
2016-03-09 15:11:23 -08:00
Tom Finegan
e020ffd183 iwyu/sample: Update includes.
Include what you use analysis based include update.

Change-Id: I51b3762ec3ffb003d19a5e26c939a71f8edf18ae
2016-03-09 15:11:18 -08:00
Tom Finegan
18834bcad0 iwyu/parser_tests: Update includes.
Include what you use analysis based include update.

Change-Id: I6bfb2c126cb8ade813e820d56bc0f965c8880c3b
2016-03-09 13:54:09 -08:00
Tom Finegan
9c00ae32e3 iwyu/muxer_tests: Update includes.
Include what you use analysis based include update.

Change-Id: I2f0c2626fe9f365a0dd9bcf47e873c1105e2e4d9
2016-03-09 13:51:34 -08:00
Tom Finegan
41a17eb108 iwyu/test_util: Update includes
Include what you use analysis based include update.

Change-Id: I92a2cb481f5475be51ffc8651782df7babe852ef
2016-03-09 13:50:56 -08:00
Tom Finegan
b6174be19d muxer_tests: Fix windows brokenness.
- Wrap MkvWriter in std::unique_ptr to allow use of the
  MkvWriter(FILE*) ctor (because MuxerTest owns the FILE*).
- Test temporary FILE* in Init(); don't assume it's valid.
- Close output FILE* before attempting to read it in
  CuesBeforeClusters().

Change-Id: I4848adec7a24c8987fdd0924e7474b264837e8a9
2016-03-08 11:25:50 -08:00
Tom Finegan
e09251510f file_util: Remove tmpnam() usage in MSVC.
Replace with windows/MSVC specific tmpnam_s().

Change-Id: I8c49e37c72630ebb14ea3c7734b96d0f79968772
2016-03-08 11:22:33 -08:00
Tom Finegan
b9dc4ac09c test_util: Don't pass NULL to std::string() in GetTestDataDir().
Change-Id: Iaafa78a17580d962e260d9553b11d2cd3cb4726f
Also: quiet MSVC warnings that suggest making code non-portable.
2016-03-08 11:15:43 -08:00
Tom Finegan
1f74651b5b webmts: Move PES/TS sources to m2ts sub directory.
Change-Id: I5c02b62460a6bf8dd73fb9274d1668a5a13af373
2016-03-07 14:32:08 -08:00
Tom Finegan
1b895e97d0 Rename libwebm_utils to libwebm_util.
Use a single naming convention.

Change-Id: Ia48089b05e5a453a402d4b4e7f258a56bee8a001
2016-03-07 14:27:07 -08:00
Tom Finegan
2fabcd344e sample_muxer: Replace std::tmpnam() with libwebm::GetTempFileName().
Change-Id: I3f26cb1ff286613de02c6017fa1246ca5c32d1e9
2016-03-07 14:27:07 -08:00
Tom Finegan
e6a0033a8c Add file_util.
Move file utility classes and functions from testing/test_util to
common/file_util, and make them part of libwebm.

Change-Id: If5b25a63b20efacc16b0fecaa8876ade4ecc4b26
2016-03-07 14:27:03 -08:00
Tom Finegan
87f9beae01 Move hdr_util to common.
Change-Id: I383680b79d798fd77bb385e1b8087967962eb230
2016-03-07 11:32:02 -08:00
Tom Finegan
1f64aaf180 cmake: Expand C++11 tests.
Change-Id: I80e0372ebe0374c3931f65c8de6410b95fb112d1
2016-03-02 13:40:32 -08:00
Tom Finegan
6dc81c1648 muxer_tests: Die immediately when unable to prep for file writing.
Change-Id: I42c4294b3089cf1a785eac3ce5ec7e47d534ea36
2016-02-29 13:44:27 -08:00
Tom Finegan
521ce4d819 webm2pes: Fix type limit warning.
Change-Id: Ic4c554209b2833e26f3e0e415693255ab2219db2
2016-02-29 13:39:26 -08:00
Tom Finegan
64c4163a15 vpxpes2ts: Fix sign-compare and type-limits warnings.
Change-Id: I18419ee5040fb2c22853d566e082369f487726e4
2016-02-29 13:38:07 -08:00
Tom Finegan
741ba686b9 muxer_tests: Replace std::tmpnam() with GetTempFileName().
Change-Id: I58d66666ba0a1ef27608265b53613dd046e7c1a3
2016-02-29 15:24:21 -05:00
Tom Finegan
6159e837e9 Merge "test_util: add missing include for close()" 2016-02-29 19:51:24 +00:00
Tom Finegan
ff81c74c97 parser_tests: Fix sign compare warnings.
Change-Id: I656f05407b88a3878920c779d49ebf89231f09f1
2016-02-29 11:33:43 -08:00
James Zern
163f57d232 test_util: add missing include for close()
Change-Id: I3825d3613e35dfdb0a5a2460a207f2d0662328f6
2016-02-27 11:11:39 -08:00
Tom Finegan
7c89eb576e Merge "test_util: Remove tmpnam() usage on non-MSVC targets." 2016-02-27 01:11:29 +00:00
Tom Finegan
c4b8686542 Merge "webm2pes_tests: Fix sign compare warnings." 2016-02-27 00:34:42 +00:00
Tom Finegan
9c9f546b25 Merge "muxer_tests: Fix sign compare warnings." 2016-02-27 00:34:07 +00:00
Tom Finegan
0fbefefb36 webm2pes: Silence sign compare warnings.
Change-Id: Ie6ce68507c35b8ec4888fe87c042e3b8371d534a
2016-02-26 16:30:24 -08:00
Tom Finegan
599e4e8bd2 cmake: Silence clang/gcc deprecation warnings.
Parts of libwebm continue to use std::auto_ptr for support of older
compilers and target systems. Silence the warnings its use causes.

Change-Id: Iac8f35c9fdaaeb1cbb637d0777b46cdad54843ed
2016-02-26 16:21:54 -08:00
Tom Finegan
82f376f356 test_util: Remove tmpnam() usage on non-MSVC targets.
Change-Id: Icd3a68fa4e52401a41f4afe52a6206d6092bc8fb
2016-02-26 11:45:35 -08:00
Tom Finegan
4d31d6bc16 webm2pes_tests: Fix sign compare warnings.
Change-Id: I92f4c18c51f26beea45246a9fa2f56a6369b9ecf
2016-02-26 11:44:06 -08:00
Tom Finegan
07ed7e01d1 muxer_tests: Fix sign compare warnings.
Change-Id: Icb549aeeb146b6dca4a89bf2b70f6fa50a893d38
2016-02-26 12:14:48 -05:00
Tom Finegan
ae2fbfe0cf parser_tests: Silence sign compare warning.
Change-Id: I5286cf99129cc8fd5336e792990886f43332b720
2016-02-26 08:57:43 -08:00
Tom Finegan
f4885281b0 libwebm_utils: Silence sign compare warning.
Change-Id: I5b8cab857f7a8a48979ee8be6bd156b854952c61
2016-02-26 08:57:43 -08:00
Tom Finegan
777247b505 Add C++11 detection to cmake file.
Disable test and webmts targets when not C++11 and/or
std::unique_ptr are unavailable.

BUG=https://bugs.chromium.org/p/webm/issues/detail?id=1136

Change-Id: I717631bc6adea90c91e59862378328089e9aeec6
2016-02-25 09:09:24 -08:00
Tom Finegan
9b89187db0 Add missing include to libwebm_utils.h.
Was missing cstdint and breaking builds on less forgiving
target systems. Also, make std namespace usage consistent.

Change-Id: I961b3ad66f8650fdebbb76a957c914c1b06e2de5
2016-02-24 14:48:41 -08:00
Tom Finegan
421874a4b5 Merge "mkvmuxer: Fix GCC build." 2016-02-22 23:50:39 +00:00
Neil Birkbeck
dd6ab35d85 Set the mastering metadata on the muxers colour
Change-Id: I456ce8409303e06a4e832cbf80cb290ad9539abc
2016-02-22 10:54:58 -08:00
Tom Finegan
8b61ef5727 mkvmuxer: Fix GCC build.
Define __STDC_LIMIT_MACROS before <climits> include.

Change-Id: I4c9c9560db1c57d177c8a7aa023c313aba5fe847
2016-02-22 09:25:19 -08:00
Tom Finegan
353b050071 Add hdr_util.
Move the Colour element utility functions out of sample_muxer and
into a place where they can be utilized by libwebm users.

Change-Id: I7e2bfd02d6f4aa4f26fb0d0a697cb68e20698655
2016-02-18 13:13:54 -08:00
Tom Finegan
c92e080f3a mkvmuxer: Use kValueNotPresent in Colour/MasteringMetadata.
Consistent with parser/no reason for unique names.

Change-Id: Ic38bc8c14413dc85fbdc28d69aa89fa0bfa7382f
2016-02-18 12:11:53 -08:00
Tom Finegan
2d0912837c Colour element: TransferFunction renamed to TransferCharacteristics.
Change-Id: I02e8d9b375d3aeba26d99866df90e25e1605143f
2016-02-18 12:03:41 -08:00
Tom Finegan
f2fc28e044 Colour element: Matrix renamed to MatrixCoefficients.
Change-Id: I148e81be6c23f0d0e61dc5820a1ae80f685af57f
2016-02-18 12:03:36 -08:00
Tom Finegan
e0b11351fb cmake: Minor CMakeLists.txt refactor.
Reduce repetition/verbosity.

Change-Id: Id2e7e0c7a6c01ee1fb118d83aa0334f71088a2af
2016-02-17 11:25:15 -08:00
Tom Finegan
1e1872bc7b Revert change from auto_ptr to unique_ptr in sample code.
This allows users of the legacy makefile on older systems without
C++11 compiler support to continue using libwebm sample code.

Change-Id: I1dd9487e0d87e355d2394fedb12ec8628a955413
2016-02-17 11:22:40 -08:00
Tom Finegan
d7fc382dea Track updates to the proposed Matroska Colour spec.
https://mailarchive.ietf.org/arch/msg/cellar/cCjxCohD-2xM93ijoFVaYYMLFas

Changes:
- ChromaSubsampling replaced by ChromaSubsamplingHorz,
  and ChromaSubsamplingVert.
- CbSubsamplingHorz and CbSubsamplingVert added.

Change-Id: I0848f9f41b3162afb5485b82704620d9e03f9b5e
2016-02-12 11:28:30 -08:00
Tom Finegan
99981ee7b9 sample(mkvparser): Output Colour element when present.
Change-Id: I6591345a4a61b909a3b5e01dbc6aba3768465717
2016-02-12 09:19:37 -08:00
Tom Finegan
375e416336 mkvmuxer: Fix Colour element support.
Colour and MasteringMetadata were treating payload size and total
size as equal:

- Internally both must use actual payload size (sum of child elements).
- External users need sum of child elements and the size of the
  respective ID.

Change-Id: Idefb193b9de394bfc6a0044f1673a62be61c6b12
2016-02-11 18:37:43 -08:00
Tom Finegan
eaeca3415d mkvmuxer: Fix bits per channel in the colour element.
Never written: copy/paste error + patch size eye glazing.

Change-Id: I2c5295b26427e0ce254b88c8b4cb5106a5f37258
2016-02-11 18:37:43 -08:00
Tom Finegan
1dab7f34ff mkvparser: Avoid crash when encountering a Colour element.
Change-Id: Iadf55bf2a7cd5535a8c2309c2d8cb6c834d30aee
2016-02-11 16:43:00 -08:00
Tom Finegan
a1517aa526 sample_muxer: copy the Colour element.
Change-Id: Ib4e8fc55351e371dd7c95abaee6f51e900c5edad
2016-02-11 10:45:51 -08:00
Vignesh Venkatasubramanian
ea9dd943b8 Merge "webm2pes: Fix tests." 2016-02-11 01:27:12 +00:00
Tom Finegan
8635c5b0a3 Merge "mkvparser: Make omitted values detectable in the Colour element." 2016-02-10 19:31:18 +00:00
Tom Finegan
ae4ae7ef77 mkvparser: Make omitted values detectable in the Colour element.
Add constants that allow users to determine when an element or value
was omitted from Colour and its child elements.

Change-Id: If909274850127938a456f2d0a1e490dcbb9c1bde
2016-02-10 09:14:34 -08:00
Tom Finegan
8c8cba6af6 webm2pes: Fix tests.
Abuse of vector::capacity and vector::reserve in combination with
abuse of vector::operator[] was a bad idea.

Change-Id: Id7bdb71888b9d0d174f5243f8cf2771d181888be
2016-02-09 20:05:32 -08:00
Tom Finegan
a281a22955 mkvmuxer: Add support for the Colour element and its children.
Change-Id: I8026a2ba6c664cbf0ce0a6602a79942283b194b1
2016-02-09 18:21:44 -08:00
Tom Finegan
41a9147f2a sample_muxer: clang-format include order fix.
Change-Id: I57ddb1d1251a1c431370a47fc5ce33996d95b973
2016-02-09 09:01:18 -08:00
Vignesh Venkatasubramanian
939a64dc2d Signal E_BUFFER_NOT_FULL in EBMLHeader::Parse
When trying to read the ebml id, signal E_BUFFER_NOT_FULL if it
occurs rather than returning E_FILE_FORMAT_INVALID (helps in case
of incremental parsing). Makes this return path consistent with
other return paths in the function.

Change-Id: I4b6ce3f0ba856959fa97f0f6ffb61994f3f2ffc6
2016-02-08 16:10:50 -08:00
Tom Finegan
fb1406ec3b mkvparser: Add support for the Colour element and its children.
Change-Id: Idffafaee221e2949c21f56c81df6e4d1c3e959a5
2016-02-08 09:23:57 -08:00
Tom Finegan
22bfdf7d99 Merge "parser_tests: Add validation of cues." 2016-02-05 18:37:15 +00:00
Tom Finegan
b873000acf parser_tests: Add validation of cues.
Make sure clusters are where the Cues element actually says they
are.

Change-Id: Ib2a4642d3bf6079d5f3985c30eeefc3b20503eaa
2016-02-05 09:48:37 -08:00
Vignesh Venkatasubramanian
799891e004 Update .gitignore to include some new binaries
Change-Id: I664abd5a35620073a12de11c5a7683fdbd16ba2d
2016-02-05 09:21:33 -08:00
Vignesh Venkatasubramanian
e051c60db1 Merge "Update muxer test gold files" 2016-02-05 17:09:11 +00:00
Vignesh Venkatasubramanian
b81d5f011c Update muxer test gold files
Some of the muxer tests have been failing because of incorrect
gold files. Updating the gold files and tweaking the tests so that
they pass in a sensible way.

Change-Id: I7d3dda6cacecda526880d6e7623f9a7678b71265
2016-02-04 16:54:00 -08:00
Tom Finegan
48b1e9a4a0 mkvparser: clang format run
Change-Id: Ib416e3ea3a955090bf4269113b36e15922107438
2016-02-04 09:56:48 -08:00
Tom Finegan
93c4690449 webm2pes: Add PES packet parsing tests.
Add test that parses the first packet output by Webm2Pes.

Change-Id: I6d2282e0e87eed759abf2483994fc767f022f0ff
2016-02-02 09:54:22 -08:00
Tom Finegan
65ca38fa20 Merge "test_util: Fix gcc build." 2016-01-26 22:14:52 +00:00
Tom Finegan
520ca6c9d0 Merge "parser_tests: Fix gcc build." 2016-01-26 22:14:39 +00:00
Tom Finegan
37a38cab9a test_util: Fix gcc build.
Change-Id: I287b8c31f354bbf871d76a4b39109dd711af7b00
2016-01-26 13:37:51 -08:00
Tom Finegan
ee0ebbaa69 parser_tests: Fix gcc build.
Change-Id: I7f29d584aad377e2a04687e778b3d07806b28882
2016-01-26 13:37:25 -08:00
Tom Finegan
c32f970f54 Replace auto_ptr usage with unique_ptr.
Change-Id: I4061686fa4739b4e5c32dfaac341dfba393dd254
2016-01-26 13:02:11 -08:00
Tom Finegan
e569ab0f7c webm2pes/ts: Fix gcc build.
Fix the build and tidy up a couple things along the way.

- Add -std=c++11 to CMakeLists.txt CXX flags.
- Add missing include to libwebm_utils.h (<memory>).
- Setup CMAKE_CXX_FLAGS properly (allow user override).
- Add missing URL for gtest repo to README.libwebm.

BUG=https://bugs.chromium.org/p/webm/issues/detail?id=1136

Change-Id: I894729216737ff92f58a7b7601484ba8fba73b25
2016-01-25 12:18:56 -08:00
Tom Finegan
2e55d6c5f7 Merge "add bitcode embedding support for ios" 2016-01-25 17:44:24 +00:00
TETRA2000
0cfb2dcbcb add bitcode embedding support for ios
BUG=https://bugs.chromium.org/p/webm/issues/detail?id=1135

Change-Id: Id3940d25216dd9fe430ce86bc1684ffe53029eb2
2016-01-23 19:24:52 +09:00
Tom Finegan
bb8cefd516 webm2ts: Converts WebM VPx video to a MPEG TS.
Built atop webm2pes, takes the output from webm2pes and packetizes it
into MPEG TS.

Change-Id: Ia122479ee91a112ad7fe223a571ca6d7ba66d406
2016-01-22 20:28:04 +00:00
Tom Finegan
453bf44d32 webm2pes: Begin addition of tests.
Just the basics:
- Some new test utilities.
- Basic setup for webm2pes testing.

Change-Id: I16bf0f5ef36e7c01f2788b2c92600d6a936bbd40
2016-01-22 11:02:34 -08:00
Tom Finegan
9299bbb6ed libwebm: Googletest integration.
Add basic mux/parse tests and test data.

Change-Id: I3bef014f32ad4898d23bca792fb3fe275fe4e7c9
2016-01-11 18:46:55 -08:00
Tom Finegan
3bec1ba7a1 Merge changes I7bcb5b3e,I8ce733be,I98a928ff,I71910f24
* changes:
  libwebm_utils: Add FileDeleter.
  webm2pes: Add a WebM parser init method.
  webm2pes: Rename Convert to ConvertToFile().
  webm2pes: Fix super frame splitting.
2016-01-06 18:40:41 +00:00
Vignesh Venkatasubramanian
5c83bbec9a Fix ParseElementHeader to support 0 payload elements
BUG=https://bugs.chromium.org/p/webm/issues/detail?id=1125

Please see the bug description for more details. This patch fixes
parsing of the file attached in the bug.

Change-Id: I2e929b6ef0ee92ea6d034b501b44a62784edf9f1
2016-01-05 13:35:00 -08:00
Tom Finegan
be35869ce3 libwebm_utils: Add FileDeleter.
Put the FILE clean up functor in a common place to avoid duplication.

Change-Id: I7bcb5b3e4df7aa37bb90920ecb8acccf94eeaa57
2015-12-17 08:50:23 -08:00
Tom Finegan
d6db1e1960 webm2pes: Add a WebM parser init method.
Pre-refactor a little to avoid some code duplication.

Change-Id: I8ce733be0c9e07544fc25bd9890d68fb14a7e84d
2015-12-17 08:50:23 -08:00
Tom Finegan
aa3593ec36 webm2pes: Rename Convert to ConvertToFile().
Change-Id: I98a928ff5b00e8961183136316be3615fd7462fe
2015-12-17 08:50:23 -08:00
Tom Finegan
e8fca12fb6 webm2pes: Fix super frame splitting.
Super frame index is at the end of the frame; not the beginning. Adjust
length to process instead of offsetting the start point for breaking up
the super frame.

Change-Id: I71910f24cc060934bb974548a29617b985985ed9
2015-12-17 08:50:17 -08:00
Tom Finegan
3cb96b6e33 webm2pes: Move main() and helper functions into their own files.
- main() and Usage() to webm2pes_main.cc
- Other helpers to common/libwebm_utils.{cc,h}

Change-Id: I59e45f0e63449066b493c4e536e0be001372504c
2015-12-17 08:38:13 -08:00
Tom Finegan
021432be9d webm2pes: Fix the linux build.
- Fix narrowing warnings in BCMVHeader::Write
- Add missing include for std::memcpy (cstring).

BUG=https://bugs.chromium.org/p/webm/issues/detail?id=1113

Change-Id: I5e89a5d4f30c9925fc6110502dc927172c709c03
2015-12-11 11:23:53 -08:00
Tom Finegan
82ac5fcdc8 Remove RELEASE.TXT.
It's stale and redundant.

Change-Id: I91c3a1e0f0c717c8f1b3ae30d648127cb2f3590c
2015-12-09 08:12:34 -08:00
Tom Finegan
852e1733a8 webm2pes: Split super frames and packetize large frames.
- PES depacketizers don't want anything but simple encoded frames.
- Large in this case means frame size + size of PES header
  is > UINT16_MAX.

Change-Id: Ifb76caaa97a0dcf3600228a0cbc4d4f2533027a7
2015-12-07 20:14:53 -08:00
Tom Finegan
faf85c227d webm2pes: Refactor header/optional header writing.
- Move class declarations to webm2pes.h.
- Add some visual demarcation between the method definitions for each
  class in webm2pes.cc.
- Reorganize the output code to make further development simpler.
- Also, clang format noise.

Change-Id: Id6d156e1f255cefe30a62784a3eadde6b93ae614
2015-12-03 14:42:37 -08:00
Tom Finegan
7c19266548 Add Webm2Pes.
Add tool for converting WebM VPx streams to Packetized Elementary
Streams.

Change-Id: I599de053df5423a803a3ea450876c52c3e400034
2015-12-02 11:42:24 -08:00
Tom Finegan
01fdee435c mkvmuxer: Disallow AddTrack() after Tracks element is output.
BUG=https://code.google.com/p/webm/issues/detail?id=1083

Change-Id: I6a603337ba5fea1333f3f1c2595f9b87b148c427
2015-10-21 09:07:00 -07:00
James Zern
1ad314e297 mkvparser: EBMLHeader::Parse: remove dead init
Change-Id: Ie06b44c3b7fd948d11aa86ae521a196ea668312b
2015-10-13 16:10:55 -07:00
James Zern
476366249e mkvparser: fix type warnings
Change-Id: Ia77a9a4e694986ece4c2e0f86f2857f320432f48
2015-09-11 18:56:09 -07:00
James Zern
267f71c76e mkvparser: SafeArrayAlloc fix type warning
num_bytes has been validated so it's safe to cast to size_t for use with
new

Change-Id: If1a6c5521dd6fbcb7e30f434b81daa3b26bd0386
2015-09-11 18:56:09 -07:00
James Zern
f1a99d5f25 mkvparser: s/LONG_LONG_MAX/LLONG_MAX/ for compatibility
Change-Id: If3b80bfd08f02ec9cba0be223ff95991564f6fd7
2015-09-11 18:56:09 -07:00
James Zern
bff1aa512d mkvparser: add msvc compatibility for isnan/isinf
fixes build errors related to these functions on visual studio prior to
2013

Change-Id: I8272f9065195e5447055aad7d0f899afa0294ea9
2015-09-11 18:55:03 -07:00
Vignesh Venkatasubramanian
a58c32339e mkvmuxer: Add codec id constant for VP10.
This was added in the libvpx's snapshot here:
https://chromium-review.googlesource.com/#/c/293861

Change-Id: I58b9635c62535ecdb0dff14dc294466262590861
2015-09-10 12:10:01 -07:00
Tom Finegan
714f3c4e4f mkvparser: validate results in EBMLHeader::Parse.
Return an error when DocType, DocTypeReadVersion, DocTypeVersion
EBMLMaxIDLength or EBMLMaxSizeLength are invalid or cannot be
handled by mkvparser.

Update samples to respect the return value from EBMLHeader::Parse.

BUG=https://code.google.com/p/webm/issues/detail?id=1057

Change-Id: I9337f13c1d5fa366b1101e48fe6bc46eb5b2ee97
2015-09-05 08:06:45 -07:00
Tom Finegan
cec98d4110 mkvparser: Correct the ReadID implementation.
Return real, known MKV IDs when reading them. Previously
IDs were treated as EBML integer values. This was both
wrong and confusing. Wrong because this results in values
that are not part of the Matroska spec, and confusing
because the code was littered with magic numbers
representing the invented IDs.

Currently uses mkvmuxer::MkvId; A TODO in the code addresses this.
Additional IDs have been added that were not previously in the enum:
mkvparser parses many elements that we do not write in the muxer.

Change-Id: I5db2b4d70d786d5239d2e2a0cbff4e7f8d844aa6
2015-09-04 09:55:59 -07:00
Tom Finegan
eb36ae4840 Merge changes I029a268e,Ia272b150,I5c4d1bbc,Ia47a2478,I3a2e2226
* changes:
  mkvparser: Cluster::Parse clean up.
  mkvparser: Disallow EBML IDs equal to 0.
  mkvparser: Cluster::Load clean up.
  mkvparser: Segment::Load asserts to error checks.
  mkvparser: Segment::PreloadCluster asserts to error checks.
2015-08-31 22:48:36 +00:00
Tom Finegan
229f49347d Merge "mkvparser: Segment::AppendCluster asserts to error checks." 2015-08-31 22:10:13 +00:00
Tom Finegan
287faf95f6 Merge "mkvparser: Segment::DoLoadClusterUnknownSize asserts to error checks." 2015-08-31 22:09:51 +00:00
Tom Finegan
1a87b59032 Merge "mkvparser: Segment assert clean up." 2015-08-31 22:09:37 +00:00
Tom Finegan
d26ec6909d mkvparser: Cluster::Parse clean up.
- Remove "// weird"'s.
- Remove commented out asserts.
- Asserts to error checks.
- Use ReadID to read IDs.

Change-Id: I029a268e4fa45931e3c6a72e41448f0b8fb2d0c3
2015-08-31 14:32:53 -07:00
Tom Finegan
f2029be5f4 mkvparser: Disallow EBML IDs equal to 0.
Change-Id: Ia272b1505dc62fdadf06348365a6aef058b081d8
2015-08-31 14:23:38 -07:00
Tom Finegan
19f5694277 mkvparser: Cluster::Load clean up.
- Remove "// weird"'s.
- Remove needless extra scoping.
- Asserts to error checks.

Change-Id: I5c4d1bbc59d9debe95e1e35e63ff0679335048ff
2015-08-31 13:59:35 -07:00
Tom Finegan
27a07c1fd1 mkvparser: Segment::Load asserts to error checks.
Change-Id: Ia47a24786789d6f94a786f76e313318e013f4f40
2015-08-31 13:38:35 -07:00
Tom Finegan
d0313dd7ce mkvparser: Segment::PreloadCluster asserts to error checks.
Change-Id: I3a2e2226f30ee047f96f5136c52e4cb9081d42c8
2015-08-31 13:36:15 -07:00
Tom Finegan
b108695b9b mkvparser: Segment::AppendCluster asserts to error checks.
Change-Id: Id6bb378b22a7c6397e3d950c2fdd84396279e881
2015-08-31 12:40:24 -07:00
Tom Finegan
4630f80f79 mkvparser: Segment::DoLoadClusterUnknownSize asserts to error checks.
Change-Id: I4597416261efb9202d2307e1ac4abfeb38e7c515
2015-08-31 12:38:20 -07:00
Tom Finegan
841a9b5fd9 mkvparser: Segment assert clean up.
- Remove asserts from ~Segment, CreateInstance, and DoLoadCluster.
- Adds new return constant (E_PARSE_FAILED == -1); most places in
  mkvparser that return -1 are the result of an internal inconsistency
  and/or misusing the API. In those cases E_FILE_FORMAT_INVALID is not
  appropriate as a return value because it's misleading to libwebm users.

Change-Id: I0d46e831b3475d69432b8745066de3329419fa11
2015-08-31 12:38:09 -07:00
Tom Finegan
8c4ca2ea04 Merge "mkvparser: Make mkvparser namespace usage uniform." 2015-08-28 21:55:13 +00:00
Tom Finegan
49ae6f0dd9 Merge "mkvparser: Fix include order." 2015-08-28 21:54:04 +00:00
Tom Finegan
0735bb5bdc mkvparser: Make mkvparser namespace usage uniform.
Instead of being weird and defining the first few functions
in mkvparser by explicitly prepending the namespace, open the
namespace immediately and define all functions within it.

Change-Id: I9a44a0fda8b04f89c8f874a2a6edc78f1b8e5bcc
2015-08-28 14:26:46 -07:00
Tom Finegan
93b24c4195 mkvparser: Fix include order.
Change-Id: Ia03ce824c78c19f5ab62c736069ea0972b8c93ea
2015-08-28 11:06:03 -07:00
James Zern
a57d6602b4 sample_muxer: fix Segment memory leak on error
use an auto_ptr<mkvparser::Segment> for compatibility which should be
harmless as there is no attempt to transfer ownership; sample.cpp
operates similarly.

Change-Id: I2cb6982aa64c62ff2ec7cbbd646770cb4e782509
2015-08-27 21:09:16 -07:00
Tom Finegan
1c5bd949d0 mkvparser: Cues, change asserts to error checks.
Change-Id: I116845b792aa5bb9a35341097cbd393300539f79
2015-08-26 12:51:05 -07:00
Tom Finegan
7f77201dca Merge "mkvparser: Add ReadID." 2015-08-26 19:49:11 +00:00
James Zern
795fd568b6 mkvparser: set kMaxAllocSize explicitly
removes the need for the unrelated INT32_MAX and fixes the build
(stdint.h was missing)

Change-Id: Idf3315097982aec6fb28030bd2327ba6cff14668
2015-08-25 20:29:50 -07:00
Tom Finegan
23bb18b76d mkvparser: Add ReadID.
Enforce ID rules in one place instead of every time
an ID is read.

Change-Id: I6e39a2e2dbafa2d5926dea790dd563cc3a48f67e
2015-08-25 13:37:35 -07:00
Tom Finegan
7b57e37fde mkvparser: add SafeArrayAlloc.
A new wrapper that makes array allocations safer by
limiting allocated size.

BUG=23430787

Change-Id: I901ee61dc2b601e8c0b5bf13f7499b5d2479ba7a
2015-08-25 13:06:27 -07:00
Tom Finegan
83a1f68944 mkvparser: Remove buf_t typedef.
- It is useless.
- It masks errors; buf_t was unsigned char*, but const buf_t was
  not seen by the compiler as const unsigned char*, which allowed
  passing a const pointer as a mutable argument to
  IMkvReader::Read at every site where buf_t was in use.

Change-Id: I293015e11c69d992e76c88ac02052a5a9a2b2c9c
2015-08-25 10:47:17 -07:00
James Zern
507471457e Merge changes Ia1265a63,I799d54df,Icfc582e4,I3425f608
* changes:
  Block::Parse: replace pos asserts w/checks
  Cluster::ParseBlockGroup: replace pos asserts w/checks
  Tags::*::Parse: replace pos asserts w/checks
  Chapters::*::Parse: replace pos asserts w/checks
2015-08-25 06:28:43 +00:00
James Zern
b18110541a Merge changes Ie4318152,I1e65f30f
* changes:
  Block::Parse: use int64 to aggregate laced frame sizes
  UnserializeFloat: check result for Inf/NaN
2015-08-25 06:25:04 +00:00
James Zern
06b4337ed8 Block::Parse: replace pos asserts w/checks
replace the common patterns assert(pos <= stop) / assert(pos == stop)
with error checks

BUG=23431751

Change-Id: Ia1265a639086c790a2ed542f34c2f438c153b036
2015-08-24 19:59:08 -07:00
James Zern
b366a98053 Cluster::ParseBlockGroup: replace pos asserts w/checks
replace the common patterns assert(pos <= stop) / assert(pos == stop)
with error checks
+ harmonize error return -1 -> E_FILE_FORMAT_INVALID

BUG=23431751

Change-Id: I799d54df62d93388b52ac325b836ab28e0860992
2015-08-24 19:59:04 -07:00
James Zern
2857b2350c Tags::*::Parse: replace pos asserts w/checks
replace the common patterns assert(pos <= stop) / assert(pos == stop)
with error checks
+ harmonize error return -1 -> E_FILE_FORMAT_INVALID

BUG=23431751

Change-Id: Icfc582e414a7d02ae0675ef14c047922c4a12036
2015-08-24 19:59:00 -07:00
James Zern
f1b2cfa03e Chapters::*::Parse: replace pos asserts w/checks
replace the common patterns assert(pos <= stop) / assert(pos == stop)
with error checks

BUG=23431751

Change-Id: I3425f6083456b5ab4f40497e3a192569b494dfa9
2015-08-24 19:56:07 -07:00
Tom Finegan
ca8062959a Merge "mkvparser: Cues::PreloadCuePoint now returns bool." 2015-08-25 02:22:05 +00:00
James Zern
6b4b297220 Block::Parse: use int64 to aggregate laced frame sizes
this is compared against a final total which is also int64

BUG=23488728

Change-Id: Ie4318152f9f9ae049a35d0b2724ccad129316981
2015-08-24 17:00:34 -07:00
James Zern
c0d2c9852b UnserializeFloat: check result for Inf/NaN
fail in either case

BUG=23488728

Change-Id: I1e65f30ff1cf857a5d1eb4bdedc3f842423cf15f
2015-08-24 16:49:22 -07:00
Tom Finegan
1a6dc4f210 mkvparser: Cues::PreloadCuePoint now returns bool.
Check allocations and fail appropriately.

Change-Id: Ie16d258a47e46b5e15c5c6275ea83ebead8b0f49
2015-08-24 16:20:13 -07:00
Tom Finegan
275ac22cae mkvparser: Cluster::Create clean up.
- Asserts to error condition check and return.
- Use nothrow new.

Change-Id: Iff9da5806e6f3240e7ea9f9e90ccdf729848a778
2015-08-24 16:19:10 -07:00
James Zern
064f2eed62 Segment::PreloadCluster(): return a bool status
BUG=23430793

Change-Id: I10aab67e94961868be806ee7ee9df550a5187e5a
2015-08-22 11:02:55 -07:00
James Zern
3778408b2a Segment::AppendCluster(): return a bool status
BUG=23430793

Change-Id: I6072234bfe211153ad143ccf7a3c6bbfa8cd166e
2015-08-22 11:01:47 -07:00
James Zern
e86d046c07 mkvparser: check Cluster::Create() return
BUG=23430793

Change-Id: Ie932dd2ee82d41368616999ab75ba3b213008642
2015-08-22 10:47:03 -07:00
James Zern
f9885b5882 mkvparser: check allocations
some unchecked new's are left in a few void functions, they'll be
addressed in a separate commit

BUG=23430793

Change-Id: I4953e70f4e7b0401a293c6b87c02445960e9ff9e
2015-08-22 10:47:03 -07:00
James Zern
21ee398281 mkvparser: Segment::Load fail w/missing info/tracks
convert asserts to error returns

BUG=23430793

Change-Id: Ifbfb5a2e7cd41344acc9c8d7afdf183b28dc2cd2
2015-08-22 10:47:03 -07:00
James Zern
08fb6546e8 Merge changes I264e68b2,Ife6190a4,Ibf37245f,I06efadb5,I88b5dfec, ...
* changes:
  mkvparser/Cluster: convert asserts to failure returns
  mkvparser/Tracks: convert asserts to failure returns
  mkvparser/Track: convert asserts to failure returns
  mkvparser/ContentEncoding: convert asserts to failure returns
  mkvparser/Cues: convert asserts to failure returns
  mkvparser/SeekHead: convert asserts to failure returns
  mkvparser/Segment: convert asserts to failure returns
2015-08-22 05:52:07 +00:00
James Zern
c8960955db mkvparser/Cluster: convert asserts to failure returns
Change-Id: I264e68b24eeb0f719a9d60b4cb0454e38110dd39
2015-08-21 22:49:57 -07:00
James Zern
680b4bfd3d mkvparser/Tracks: convert asserts to failure returns
BUG=23431751

Change-Id: Ife6190a4bcd4ab949165f17fd0b6c26a058a661b
2015-08-21 22:49:57 -07:00
James Zern
5889e6c18b mkvparser/Track: convert asserts to failure returns
Change-Id: Ibf37245f74e019c788b3f4121082956aa209430a
2015-08-21 22:49:57 -07:00
James Zern
5135c4cd74 mkvparser/ContentEncoding: convert asserts to failure returns
Change-Id: I06efadb5242135b095ad4cdefceef0e1c42c79b9
2015-08-21 22:49:57 -07:00
James Zern
b0e4f32011 mkvparser/Cues: convert asserts to failure returns
Change-Id: I88b5dfecfd03fec7f5808959ec6f640bff838d7a
2015-08-21 22:45:02 -07:00
James Zern
13ccc7f089 mkvparser/UnserializeInt: fix sign flip
with -funsigned-char the sign will be flipped, e.g., -128 -> 128, use an
explicit signed char.

additionally drop the misguided range check; this is meant as a data
size limit not one for the big-endian encoded ints

Change-Id: Ia10ef811d16acd09cbcd3d95856d9c460c9b7f16
2015-08-21 22:35:20 -07:00
James Zern
db3f9bbd79 mkvparser/SeekHead: convert asserts to failure returns
Change-Id: Ic2c83e4eb246fd4c1fc63fe16298f0dc78801912
2015-08-21 19:47:34 -07:00
James Zern
8de3654fdb mkvparser/Segment: convert asserts to failure returns
Change-Id: I7ccfd5be5e7438561edacb06bc8e6256aa6e0369
2015-08-21 19:46:15 -07:00
James Zern
fa2aa7da2d SeekHead::Parse(): fix assertion failure
replace assertions with failure returns

BUG=23430787
BUG=23431751

Change-Id: I22f000388cf040d064ba898c5de3658b56a3dfea
2015-08-21 18:12:08 -07:00
James Zern
d9bdadeff8 sample{,_muxer}: check SegmentInfo::GetInfo() return
prevents a segfault when parsing a corrupt file

BUG=23430793

Change-Id: I909fd456555ed0d5d871e12258b4887f36f90867
2015-08-21 16:58:04 -07:00
James Zern
07a9cf7127 Merge "mkvparser: Remove some asserts." 2015-08-21 21:28:13 +00:00
Tom Finegan
c56ee29254 mkvparser: Remove some asserts.
Remove asserts in sections recently updated to do error checking, and
replace some additional nearby asserts with error checks.

Change-Id: Ia8b60824736a7a821bbca3f2bfef5de4bb584c2d
2015-08-21 13:06:09 -07:00
Tom Finegan
d9013243ff Merge "mkvparser: Remove some asserts from SegmentInfo::Parse." 2015-08-21 19:57:35 +00:00
Rob Gaunt
7f7d898a27 Fix case sensitivity issue in iosbuild.sh.
Change-Id: I82b851b442cfe46ead78d115bbd7e22927ea6334
2015-08-21 12:27:30 -07:00
Tom Finegan
42fe2cd755 mkvparser: Remove some asserts from SegmentInfo::Parse.
Just return errors.

Change-Id: Ic3510db9c298e12cbe2a40fe09344a1c8e1e4ca8
2015-08-21 12:10:38 -07:00
Tom Finegan
8bccd9c306 Merge "mkvparser: avoid rollover in UnserializeInt()." 2015-08-21 18:47:16 +00:00
Tom Finegan
7a2fa0daf3 mkvparser: avoid rollover in UnserializeInt().
- Not strictly rollover-- avoid exceeding max 64 EBML (2^26 - 2).
- Tidy up the function.

BUG=23321923

Change-Id: I172c75064c189ed0fcf224145d016fca421f60c6
2015-08-21 11:24:30 -07:00
Tom Finegan
44f5ce64b1 mkvparser: Disallow durations in seconds greater than LONG_LONG_MAX.
libwebm cannot handle a duration in seconds greater than LONG_LONG_MAX
because it stores the values in long long variables.

BUG=23321923

Change-Id: Idb73f04a73e35829ae34386ea6c388fd355dd102
2015-08-21 10:54:27 -07:00
Tom Finegan
b521e3030e Merge "mkvparser: Segment::ParseHeaders() avoid rollover and bad int sizes." 2015-08-20 16:59:29 +00:00
Tom Finegan
7680e2a76b mkvparser: Check for errors in Match().
Confirm asserted conditions are as expected in all build
configurations, and avoid rolling over pos in obvious places.

BUG=23225325

Change-Id: I8af3192283788fd4a4b5b8ba4ad94abeab7feff2
2015-08-19 21:46:32 -07:00
Tom Finegan
39a315f8c1 mkvparser: Segment::ParseHeaders() avoid rollover and bad int sizes.
BUG=23226908

Change-Id: I177fc75684daa3c0282b63ec270d095251a70881
2015-08-19 21:23:21 -07:00
Tom Finegan
f250aceeaa mkvparser: Handle invalid lengths and rollover in ParseElementHeader().
BUG=23224239

Change-Id: I597054dc552b54f99a6716fb8f1b0f2480f2a29b
2015-08-19 12:34:54 -07:00
Tom Finegan
cd96a76985 mkvparser: Avoid rollover/truncation in UnserializeString().
Change-Id: I355d00b59ec1b7645ae5b4010e292215b5da3a17
2015-08-17 15:35:44 -07:00
Tom Finegan
8e8b3dbc6a Merge "mkvparser: Add error checking in Block::Parse." 2015-08-14 18:11:24 +00:00
James Zern
82b7e5f487 sample: correct mbstowcs() error check
mbstowcs() can return (size_t)-1 if it encounters an invalid string

BUG=23200382

Change-Id: Ibf67145be3989e16cd24c06850c7a5aa581a0ada
2015-08-14 10:57:48 -07:00
James Zern
04d7809375 sample: check allocation return
BUG=23200382

Change-Id: Ic64f76000d181f169af9aed2f7891f6ed3d28681
2015-08-14 10:57:01 -07:00
Tom Finegan
986b64b8c0 mkvparser: Add error checking in Block::Parse.
Instead of relying solely on asserts, which compile away to
nothing in downstream projects using libwebm for parsing webm
input streams, actually check for the conditions being asserted,
and return errors when appropriate.

Change-Id: Id8b6352e8dda69782129dcea8f67203fd9c4f572
2015-08-14 10:45:46 -07:00
James Zern
2dec09426a mkvparser: normalize UnserializeInt signature
long size -> long long; fixes a conversion warning under visual studio

Change-Id: I216151236f4ad7e1b8af4d8b7d19e3b36083fd14
2015-08-04 19:01:06 -07:00
Francisco Facioni
b6de61a5c0 Adds support for simple tags
Change-Id: I285e4b73df0a7112bbde7ef13eddf8fdccf59178
2015-07-22 17:07:25 -03:00
Tom Finegan
75a6d2da8b sample_muxer: Don't write huge files.
sample_muxer was using the buffer size instead of the frame payload size
when passing frames to the muxer.

BUG=https://code.google.com/p/webm/issues/detail?id=1032

Change-Id: I25578934e8822553e3482ded80eaf22651be85cc
2015-07-01 14:26:55 -07:00
James Zern
cec1f8521f mkvmuxer: remove unused timecode_scale variable
unused in WriteFramesAll() / WriteFramesLessThan() since:
d6d04ac mkvmuxer: use generic Cluster::AddFrame

Change-Id: I2089dc24b6a942f342b278b46271c6144cf8351e
2015-06-17 16:23:30 -07:00
James Zern
8a61b4033e Merge "mkvparser: Tiny whitespace fix." 2015-06-10 19:10:17 +00:00
Vignesh Venkatasubramanian
7affc5c3f8 clang-format re-run
Re-run clang-format to pick up some missed changes over the past
few CLs. Also update the .clang-format file to break after ternary
operator.

Change-Id: Ia4ba4e58362c2dbe36aeb33894f0411af33ef17d
2015-06-04 16:48:48 -07:00
Vignesh Venkatasubramanian
d6d04acdcc mkvmuxer: use generic Cluster::AddFrame
Replace specific Cluster::AddFrame* calls with a call to generic
Cluster::AddFrame().

Change-Id: If082490d2c29003b466034fc318f5e58791408a6
2015-06-04 16:33:36 -07:00
Vignesh Venkatasubramanian
4928b0bd5f Merge "mkvmuxer: Write Block key frames correctly." 2015-06-04 23:32:33 +00:00
Vignesh Venkatasubramanian
c2e4a46244 Merge "sample_muxer: Use AddGenericFrame to add frames." 2015-06-04 23:17:14 +00:00
Tom Finegan
e97f296855 mkvparser: Tiny whitespace fix.
Change-Id: I0f17eee0ce161c950f6d504ba1b509bd7b0e6343
2015-06-04 09:55:58 -07:00
Frank Galligan
d66ba4470a Merge "Add support to parse DisplayUnit." 2015-06-03 00:25:32 +00:00
Frank Galligan
deb41c2ea1 Add support to parse DisplayUnit.
BUG=https://code.google.com/p/webm/issues/detail?id=1009

Change-Id: I209ee6caf5bc10dfc1761e650821cc2338a4b13c
2015-06-02 16:17:13 -07:00
Leonel Togniolli
42e5660e73 Fix issues on EBML lacing block parsing
Fix EBML lacing block parsing when attempting to parse the last frame
on single-frame videos and assertion when frame_count is lower
than actual data in the file.

Change-Id: I223e30be54970ef75126c6c4ee3401cbeb92e02f
2015-06-02 15:51:48 -07:00
Leonel Togniolli
fe1e9bba6e Fix block parsing to not allow frame_size = 0
Fixed block parsing to account to cases that would
allow frame_size = 0, only to be rejected later on
Block::GetFrame assert(f.len > 0);

Change-Id: Idb93388b37e1963ec6115ac49f15e4951bc2c724
2015-06-02 15:51:48 -07:00
Leonel Togniolli
2cb6a28b09 Change assertions to checks when parsing TrackPositions
Malformed files woudl cause the parser to assert.

Instead now it stops parsing and skips the segment.

Change-Id: I256b3b72e43f969693ae16547ca98da07d665e21
2015-06-02 15:51:40 -07:00
Leonel Togniolli
d04580fda5 Fixes issues on Block Group parsing
Changed assertions to "invalid file format" errors files that
had Block Groups without Block IDs or had invalid sizes or
durations

Change-Id: I1383a63bfb76ee46aaa0aff089780383ce65fc31
2015-06-02 10:39:09 -07:00
Vignesh Venkatasubramanian
c3550fdacf mkvmuxer: Write Block key frames correctly.
Per matroska Block Structure [1], for keyframes the flag should not be
set (unlike SimpleBlocks). For Blocks, keyframes is inferred by the
absence of ReferenceBlock element.

This CL fixes Issue #933 [2].

[1] http://www.matroska.org/technical/specs/index.html#block_structure
[2] https://code.google.com/p/webm/issues/detail?id=933

Change-Id: Ia3f811c3fe17fb4dededda2f6834cf7cf2d2e022
2015-06-01 11:04:12 -07:00
Vignesh Venkatasubramanian
5dd0e40dbd Merge "mkvmuxer: Set is_key to true for metadata blocks." 2015-06-01 17:51:40 +00:00
Vignesh Venkatasubramanian
8e96863b56 mkvmuxer: Set is_key to true for metadata blocks.
Per matroska semantics, all metadata blocks should be considered
key frames. Set it to true in AddMetadata functions.

Change-Id: Ibc26845dc6cc72ccbf90ae8d4dcc27c948e8a375
2015-06-01 10:49:19 -07:00
Vignesh Venkatasubramanian
a9e4819e9f sample_muxer: Use AddGenericFrame to add frames.
Use Segment::AddGenericFrame to add frames to the output file. The
other AddFrame* functions will soon be deprecated and this will be
the preferred way of adding frames.

Change-Id: I3ed862543a1e0199617dc613a1760ff5f233ce7d
2015-06-01 10:32:07 -07:00
Leonel Togniolli
5a3be734f3 Change assertions to checks when load CuePoints
Malformed files would cause the parser to assert.

Instead now it stops parsing and skips the segment.

Change-Id: I07e3baf5c9eb6feb115e155f226d8abc2c37698e
2015-05-25 01:27:38 +01:00
James Zern
f99f3b20fb mkvmuxerutil::EbmlDateElementSize: remove value param
this is unused as the size of dates is fixed:
Date - signed 8 octets integer in nanoseconds with 0 indicating the
precise beginning of the millennium (at 2001-01-01T00:00:00,000000000
UTC)

Change-Id: I7d44c92a6b746e92e4041238b110115b56e38a93
2015-05-23 10:33:12 -07:00
James Zern
ff572b5399 Frame::IsValid: fix track_number check
previously IsValidTrackNumber() expected a track_number > 0
this also fixes a warning:
'comparison of unsigned expression < 0 is always false'

Change-Id: I839863986ff776aae59e38ee7e4a1a710081303a
2015-05-23 10:32:56 -07:00
Vignesh Venkatasubramanian
b6311dc16f mkvmuxer: Refactor to remove a lot of duplicate code
Refactor muxer to remove a lot of duplicate code. This CL strives
to not change the API as much as possible. Although, there is one
minor public API change (constructor of the Cluster class). Other
than that, all the functions should work exactly the same way as
before.

Following up on this CL, we are going to make AddGenericFrame the
preferred way of adding frames to a segment and deprecate (and
eventually remove) all the other specific AddFrame* functions.

Change-Id: Ie410f1a64a981e1545ade53ce476bbe8b3610c4f
2015-05-20 10:24:26 -07:00
Vignesh Venkatasubramanian
256cd02327 Merge "mkvmuxer: DiscardPadding should be signed integer." 2015-05-14 13:42:50 +00:00
Vignesh Venkatasubramanian
16c8e78265 mkvmuxer: s/frame/data in all AddFrame* functions.
Rename variable "frame" to "data" in all the AddFrame* functions.
This is in prepararation for a follow-up CL.

Change-Id: Ifd0d96cfbeca85c12be23d854bc87e085436984d
2015-05-12 15:31:07 -07:00
Vignesh Venkatasubramanian
c5e511c00a mkvmuxer: DiscardPadding should be signed integer.
Discard Padding getter and setter should take and return a signed
integer respectively.

Change-Id: Ieb6b9cd8c9830c2335ffdbcd608c727a3d135bb8
2015-05-12 14:56:12 -07:00
Tom Finegan
4baaa2c9a3 Add framework build script: iosbuild.sh
Builds WebM.framework.

Change-Id: I6f71defa18a7cbb21e290dbbb819a85353912e53
2015-05-06 10:33:48 -07:00
James Zern
3d06eb1e2c PATENTS: fix a typo: constitutes -> constitute
Change-Id: Iec2d5fea1b89fc97f981f5cd0a545b83110bd8c2
2015-04-30 15:40:13 -07:00
Tom Finegan
d3849c2f7b mkvparser: Dead code removal.
Change-Id: Ic4cf359ecc80641b97f40c20639ce9c32b34077d
2015-04-14 23:36:29 -07:00
Leonel Togniolli
f439e523b8 Change assertions to checks when preloading Cues
If a malformed webm file contains invalid information on the Cues
the segment, the parser would assert.

Instead, now it ignores the Cues and skips the segment.

Change-Id: I9270f6a0935ce9e9a3765a5f324ae542c1ade1c7
2015-04-14 01:25:25 +01:00
Leonel Togniolli
d3a44cd549 Fix track transversal when listing Cues on sample
It could skip tracks or crash if track numbers were non-sequential or tracks were missing.

Change-Id: I485bd4c14c73500775f2944b4486f9a5e154a5e8
2015-04-11 00:24:30 +01:00
Leonel Togniolli
c6255af02a Tweak .gitignore so git status is clean after checkout and build:
- added missing underscore to sample_muxer
- added cmake and make related files

Change-Id: Id9a6f12be83d28c95941098b57b61a7a11510f1b
2015-04-09 00:38:17 +01:00
James Zern
b5229c7bc8 Makefile.unix: s/samplemuxer/sample_muxer/
this matches the target name used in CMakeLists.txt and the writing app
stored in the output file

Change-Id: I161675c6bff8ebfa041331a329589441d3874514
2015-03-18 15:33:06 -07:00
Sasi Inguva
e3616a6614 Add support to parse stereo mode, display width and display height in mkvparser
Change-Id: I7ff99275b70e96b84601c32836f1b79f95fcf0d4
2015-03-12 00:25:58 -07:00
Vignesh Venkatasubramanian
a4b68f825e parser: Fix bug in Chapters::Atom::Parse()
Reading the UID is considered to be failed only if status is < 0
and not the value read.

Change-Id: I88fee3aa5b8c323d099930a6823406c012b70f81
2015-03-03 12:08:28 -08:00
Tom Finegan
bab0a002c5 cmake: Set library and project name the proper way on Windows.
Revert previous hack and use target properties to correct project
and library names.

Change-Id: Ib35da1cedcedf86f3f020d879cd39199fd236572
2015-03-02 12:43:56 -08:00
Tom Finegan
feeb9b13ff Set library name to match Windows expectations.
Back to libwebm.lib from webm.lib.

Change-Id: I6ced362c987a7b5d3d56365a1ed53de7bf9f849b
2015-02-25 15:37:05 -08:00
Vignesh Venkatasubramanian
b9a549b467 Fix CMakefile to generate libwebm.a
The existing CMakeLists.txt ends up generating a static library
with name "liblibwebm.a" rather than "libwebm.a". This patch fixes
it.

Change-Id: I4dabac5158530714a38045b8af29e75ade0a939e
2015-02-25 14:04:04 -08:00
Tom Finegan
b386aa5c6b Add CMakeLists.txt and msvc_runtime.cmake.
- These files facilitate project/makefile generation.
- Remove old Visual Studio projects.
- Rename Makefile to Makefile.unix.

Change-Id: If786edd75d44c462538526c286eccc5cbf15d828
2015-02-13 16:07:01 -08:00
Vignesh Venkatasubramanian
b0f8a81df9 parser: Fix memory leak in Chapter parsing
Fix a memory leak in parsing Chapters element.

Change-Id: I95324299014174d3f0926d96022eeb747b07d1a7
2015-02-06 15:17:28 -08:00
Vignesh Venkatasubramanian
f06e152abd mkvmuxer: Fix MoveCuesBeforeClustersHelper recursive call.
The third parameter of the MoveCuesBeforeClustersHelper recursive function
should always be the size of the cues element without the master element's size
(i.e.) it should be the sum of size of all Cue Points. This way, the changes in
the Length of the master element itself will be computed correctly.

Change-Id: I05ff1606fb74168f80ffed81fd3c0de3f237c579
2015-02-02 18:34:18 -08:00
Lajos Molnar
27bb7476dd allow subtitle tracks with ContentEncodings
This is allowed by matroska spec

Change-Id: I1842b6e7c6bab4ba0f86938bbe6b110be0c5435f
2015-01-13 12:56:25 -08:00
James Zern
623d182613 DoLoadCluster: tolerate empty clusters
previously only empty clusters of known size were accepted; with
clusters of unknown size the cluster has been successfully parsed and a
working copy of the file position updated, so parsing can continue.
clusters of this type are discarded as clusters of known size currently
are.

Change-Id: I3ef848768519ab7f1887a11629c50af72249cead
2014-10-01 12:53:14 -07:00
Lou Quillio
1156da8d29 Update PATENTS to reflect s/VP8/WebM/g
Sync with http://www.webmproject.org/license/additional/

modified:   PATENTS.TXT

Change-Id: I3e1b3a570b26ada0e6e0d344f1783ef0e3cd5fa1
2014-08-11 14:30:54 -07:00
Tom Finegan
0d4cb404ea mkvmuxerutil: Use rand() in MSVC builds.
Instead of rand_s(), which can make things unpleasant for downstream
projects.

Change-Id: Ie172867c28aaa43223dc5fb694eb4a4fd26515d6
2014-07-18 11:37:06 -07:00
Vignesh Venkatasubramanian
e12fff0ebb mkvmuxer: Overload WriteEbmlHeader for backward compatibility
WriteEbmlHeader function was updated on
a321704b4c7f90793ffe55497978fe7b6676944c. It is a public function that
is exposed outside of the library. Overload it with an old signature
to maintain compatibility. The overloaded function writes the
doc_type_version as 2 by default (thereby retaining the old behavior).

Change-Id: If887a1bfa3e81e7e639c986a922aa5155faab2cf
2014-07-09 11:24:09 -07:00
James Zern
a321704b4c mkvmuxer: write correct DocTypeVersion
Change-Id: I9a463394dec5e69ae8a7b5a1378f19d390e441e4
2: default
4: if CodecDelay/SeekPreRoll/DiscardPadding are present
2014-06-24 16:17:29 -07:00
James Zern
574045edd4 mkvmuxer: fix DiscardPadding
DiscardPadding is a signed int.
this change fixes 2 things:
- allows negative values for discard padding
- fixes cases where an unsigned value would be written such that on read
  the sign would be flipped

Change-Id: I9418da7a22c09768e02d5b61da8d01c2bccb5dee
2014-06-18 12:50:25 -07:00
Sergey Ulanov
8be63972fd Include crop elements when calculating size of Video element
Change acf788 added Crop* elements support, but they were not
added when calculating size of Video element.

Change-Id: I64495cc35406a28b86b40d915dbc291f45aa1263
2014-06-06 00:40:50 -07:00
James Zern
8f2d1b3cde mkvparser: fix DiscardPadding extraction
the element length was being read twice; the second attempt would
consume a portion of the discard padding field often failing due to
limitations in GetUIntLength.

Change-Id: Ibbe3f082e2d05460734a0e1f7d23f3c665e3f24b
2014-05-30 14:44:28 -07:00
Vignesh Venkatasubramanian
1c36c24694 mkvmuxer: fix style guide violations
fix a few style guide violations in mkvmuxer.cpp

Change-Id: If800a5d6851f8ba4b904341fd054e1c2091e281e
2014-05-29 08:30:30 -07:00
Vignesh Venkatasubramanian
568504e64e Merge "UUIDs can have their high bit set" 2014-05-23 09:01:20 -07:00
Sergey Ulanov
acf788bedd Add support for CropLeft, CropRight, CropTop and CropBottom elements.
Change-Id: Ic5993a3e04b3eefccc3016fbe6b49d1e4a5fc05d
2014-05-21 19:46:36 -07:00
Vignesh Venkatasubramanian
418188b03e Merge "muxer: codec_id is a mandatory element" 2014-05-18 12:48:29 -07:00
Vignesh Venkatasubramanian
07688c92d7 mkvmuxer: Reject frames if invalid track number is passed.
Reject frames if an invalid track number is passed. Also change sample_muxer
to reject files which have Block elements with invalid track numbers.

Fixes Issue #659: https://code.google.com/p/webm/issues/detail?id=659

Change-Id: Ie6cf39a409b68bb4d2261f308409ee0c36d5dd8e
2014-05-18 12:45:49 -07:00
Vignesh Venkatasubramanian
2a63e473d8 muxer: codec_id is a mandatory element
codec_id element for a Track is mandatory and it does not have a default.
Rejecting the file if that happens.

Change-Id: I4fb0dfcd4c09eeabf22634db7fdf6ca818c93917
2014-05-16 11:42:05 -07:00
Vignesh Venkatasubramanian
d13c017744 UUIDs can have their high bit set
mkvparser::UnserializeUInt() assumes that unsigned values never have
their high bit set. This is too limiting for UUIDs. In addition, the
Chapters::Atom::Parse() method would truncate a "negative" 64-bit UUID
value to 32 bits and return the truncated value as a status code.
This value then might or might not be treated as an error by the caller
depending on whether the truncated value was itself negative.

Change-Id: I15624ac62d0b02691a1405ee6a5f7eb441b3bc48
2014-05-16 11:25:22 -07:00
James Zern
249629d46c make Mkv(Reader|Writer)(FILE*) explicit
Change-Id: I2c6e0df3049903f8ea53babeacffaa87f6c222b0
2014-05-02 11:47:44 -07:00
Vignesh Venkatasubramanian
7f3cda494a mkvparser: fix a bunch of windows warnings
fix a bunch of windows warnings in parser.

Change-Id: Ia9a03879540595306d8fa2b90ceb9b3b5b0d93a6
2014-05-01 13:50:19 -07:00
Vignesh Venkatasubramanian
5c0617852f Merge "clang-format on mkvparser.[ch]pp" 2014-05-01 11:50:03 -07:00
Vignesh Venkatasubramanian
4df111e60a clang-format on mkvparser.[ch]pp
Conformance of mkvparser.[ch]pp to Google C++ style guide.

Change-Id: I459adac3da1496b432b71b3580b4dbd63037df2b
2014-04-29 11:30:00 -07:00
Vignesh Venkatasubramanian
7b2450131c clang-format re-run.
Re-running clang-format to take into account the recent change in it.
(https://gerrit.chromium.org/gerrit/#/c/69926/ )

Change-Id: Ie11afcaaf07a1967f65fd765f1a7c7112c85875a
2014-04-29 11:27:31 -07:00
Vignesh Venkatasubramanian
c6767b94fd Change AlignTrailingComments to false in .clang-format
AlignTrailingComments set to true seems to be causing some unwanted
alignments. Turning it off.

Change-Id: I5fd99db90b00c76cc7891f2cd1c80ec69ae97697
2014-04-29 00:38:14 -07:00
Vignesh Venkatasubramanian
9097a0691b Merge "muxer: Reject file if TrackType is never specified" 2014-04-29 00:18:55 -07:00
Vignesh Venkatasubramanian
eddf9744cb Merge "clang-format on mkvmuxertypes.hpp and webmids.hpp" 2014-04-28 10:40:43 -07:00
Vignesh Venkatasubramanian
def325c010 muxer: Reject file if TrackType is never specified
According to matroska specification, TrackType is a mandatory element without a
default value [1]. But we have been producing invalid matroska files when
TrackType is never specified because we write 0 by default.

This patch will reject writing a track without specifying the TrackType value.
Specifically, this path will be triggered when Segment::AddTrack() is called
but there is no subsequent call to Track::set_type().

[1] http://www.matroska.org/technical/specs/index.html#TrackType

Fixes issue #769: https://code.google.com/p/webm/issues/detail?id=769

Change-Id: I4d75d169fd96c7e1fad278561f0e7a3e1135989c
2014-04-26 03:14:05 -07:00
Vignesh Venkatasubramanian
41f869cb0c Merge "clang-format on webvttparser.(cc|h)" 2014-04-25 22:19:26 -07:00
Vignesh Venkatasubramanian
fd0be37ba4 clang-format on webvttparser.(cc|h)
Conformance of webvttparser.(cc|h) to Google C++ style guide.

Change-Id: I19610c5795c0bd2446c07a6c2abde58c3286b2ea
2014-04-25 22:18:40 -07:00
Vignesh Venkatasubramanian
207d8a193a Merge "clang-format on mkvmuxerutil.[ch]pp" 2014-04-25 22:09:48 -07:00
Vignesh Venkatasubramanian
02429eb11b Merge "clang-format on mkvwriter.[ch]pp" 2014-04-25 22:09:17 -07:00
Vignesh Venkatasubramanian
0cf7b1b7d3 Merge "clang-format on mkvreader.[ch]pp" 2014-04-25 22:09:02 -07:00
Vignesh Venkatasubramanian
2e80fedf8c Merge "clang-format on sample.cpp" 2014-04-25 22:08:38 -07:00
Vignesh Venkatasubramanian
3402e12d1a Merge "clang-format on sample_muxer.cpp" 2014-04-25 22:08:27 -07:00
Vignesh Venkatasubramanian
1a685db45b Merge "clang-format on sample_muxer_metadata.(cc|h)" 2014-04-25 22:07:59 -07:00
Vignesh Venkatasubramanian
6634c7f87a Merge "clang-format on vttreader.cc" 2014-04-25 22:07:46 -07:00
Vignesh Venkatasubramanian
7566004462 Merge "clang-format on vttdemux.cc" 2014-04-25 22:06:42 -07:00
Vignesh Venkatasubramanian
9915b8408e clang-format on mkvreader.[ch]pp
Conformance of mkvreader.[ch]pp to Google C++ style guide.

Change-Id: I9928a1a7daf9afaa30355b17b3eeeb2966626031
2014-04-15 12:05:58 -07:00
Vignesh Venkatasubramanian
743725477c clang-format on mkvmuxertypes.hpp and webmids.hpp
Conformance of mkvmuxertypes.hpp and webmids.hpp to Google C++ style guide.

Change-Id: Ib5e524f75f04ae6f6f5f24600d70b8448d01964c
2014-04-15 11:39:44 -07:00
Vignesh Venkatasubramanian
0d5a98cee5 clang-format on sample_muxer.cpp
Conformance of sample_muxer.cpp to Google C++ style guide.

Change-Id: I8d7ef884fbaac8ebbf12fc3e3215532ced5ac29b
2014-04-15 11:36:43 -07:00
Vignesh Venkatasubramanian
e3485c9b9f clang-format on vttdemux.cc
Conformance of vttdemux.cc to Google C++ style guide.

Change-Id: Id8838ddec286f935c8a3c1b78d9d9027b467165f
2014-04-15 11:31:20 -07:00
Vignesh Venkatasubramanian
46cc823994 clang-format on dumpvtt.cc
Conformance of dumpvtt.cc to Google C++ style guide.

Change-Id: I5fa11e79e95e61c1a1d923ba76ac7ae343c9c8e4
2014-04-14 12:15:04 -07:00
Vignesh Venkatasubramanian
5218bd291c clang-format on vttreader.cc
Conformance of vttreader.cc to Google C++ style guide.

Change-Id: Id5d2baf0977bca9ab938831cf6e6204acd4ed647
2014-04-14 12:11:27 -07:00
Vignesh Venkatasubramanian
1a0130d069 clang-format on sample_muxer_metadata.(cc|h)
Conformance of sample_muxer_metadata.(cc|h) to Google C++ style guide.

Change-Id: I500a8cdbc443981ecae6ac2a7d8de7cab1c72e28
2014-04-14 12:09:20 -07:00
Vignesh Venkatasubramanian
867f1894da clang-format on sample.cpp
Conformance of sample.cpp to Google C++ style guide.

Change-Id: Icb6bfce6af5df04775a086e080e6fa742c6d68f9
2014-04-14 12:05:21 -07:00
Vignesh Venkatasubramanian
4c7bec5743 clang-format on mkvwriter.[ch]pp
Conformance of mkvwriter.[ch]pp to Google C++ style guide.

Change-Id: I997545b366277b7f1235b9fa7cc30a4969098553
2014-04-14 10:30:33 -07:00
Vignesh Venkatasubramanian
9ead078aaf clang-format on mkvmuxerutil.[ch]pp
Conformance of mkvmuxerutil.[ch]pp to Google C++ style guide.

Change-Id: Ib66b73adb2682cd5560f6f363fc04d75ab3815c6
2014-04-14 10:28:59 -07:00
Vignesh Venkatasubramanian
fb6b6e6444 clang-format on mkvmuxer.[ch]pp
Conformance of mkvmuxer.[ch]pp to Google C++ style guide.

Change-Id: I9bcd14710adbad4f32aa1a6be2ea7e40fb715e91
2014-04-11 11:41:01 -07:00
Vignesh Venkatasubramanian
ce775929a6 Update .clang-format to allow short functions in one line
Update .clang-format so that it allows short functions and constructors in a
single line if it fits.

Change-Id: I60788089fc7a4e2f4c4df6947368ebc0f3fa8c49
2014-04-11 11:24:46 -07:00
Tom Finegan
0a24fe44ae Merge "Add support for DateUTC and DefaultDuration in MKV Muxer." 2014-04-10 16:13:21 -07:00
Vignesh Venkatasubramanian
11d5b66eb4 Merge "Add .clang-format" 2014-04-09 11:55:47 -07:00
Vignesh Venkatasubramanian
a1a3b14538 Add .clang-format
Add .clang-format file so that it can be used to maintain
the same style throughout the library.

Change-Id: I22bd21055f565a886b5a880856810f4b35b22cce
2014-04-09 11:50:54 -07:00
Sergey Ulanov
0fcec38045 Add support for DateUTC and DefaultDuration in MKV Muxer.
BUG=crbug.com/321825

Change-Id: I5ff8c5b9fd4e6be23ef2bc91a7a4ba021db6441f
2014-04-08 21:48:00 -07:00
Vignesh Venkatasubramanian
a7118d8ec5 Fixing a warning in mkvmuxerutil.cpp
Changing a constant from int32 to uint64 to fix a warning in
mkmuxerutil.cpp

Change-Id: Ifd9f76ea4be848eff4d98a797d2d4dcd22f11478
2014-04-08 16:15:28 -07:00
Vignesh Venkatasubramanian
abe9c2d0d1 Adding support for user file ownership in MkvReader
Adding a constructor to MkvReader that will enable user application
ownership of the file.

Change-Id: I10f8f71715392df3d4b78c7c11076e19c30e1af6
2014-04-04 13:49:52 -07:00
Vignesh Venkatasubramanian
630a0e3c33 mkvmuxerutil: Getting rid of strict-aliasing warning
Replacing a reinterpret_cast from float& to uint32& with a union to get rid of
"dereferencing type-punned pointer will break strict-aliasing rules" warning.
This warning is produced on passing -O3 in gcc.

Change-Id: Ie942597f418e3659e3ff29a909c43dd99266c04d
2014-03-17 12:19:21 -07:00
Vignesh Venkatasubramanian
e369bed319 Support user ownership of files in MkvWriter
Overloading MkvWriter's constructor so that it can wrap a user owned
FILE pointer. Doing this so that applications which handle the file opening
and closing by themselves don't have to have their own implementation of the
IMkvWriter interface.

Change-Id: I69c57f3e6927ea13b616c425e3b5f179d2e69215
2014-03-12 12:48:17 -07:00
Tom Finegan
a9d94ef2c5 Merge "vttdemux: Add VS2013 project." 2014-03-10 11:49:55 -07:00
Tom Finegan
3b66306126 vttdemux: Add VS2013 project.
And add it to the libwebm VS2013 solution.

Change-Id: I9957b47b291722bc0e5eb435795252cf780f968b
2014-03-10 11:46:53 -07:00
Tom Finegan
acb7a2c8bc Add VS2010 DLL build configurations for vttdemux.
- Link to libwebm instead of building sources.
- Add missing dependency on libwebm.

Change-Id: I8f977f767f6104d07f716c7c5ebecda249c202f2
2014-03-07 16:53:47 -08:00
Tom Finegan
99f40649a7 Merge "mkvmuxer: Silence MSVC warning that suggests making code non-portable." 2014-03-06 16:40:59 -08:00
Matthew Heaney
c6634bca44 Merge "vttdemux: created win32 project" 2014-03-06 14:36:03 -08:00
Matthew Heaney
17cf7cc519 vttdemux: created win32 project
Change-Id: I2a1ce12bc374f7493c50021cbe4fc4a4716a6829
2014-03-06 14:31:02 -08:00
Tom Finegan
7f79df14a8 Add Visual Studio 2013 projects.
Basically identical to the 2010 projects, but with platform
toolset set to VS 2013, and output files/paths updated to
avoid collisions with VS 2010 output.

Change-Id: I02b827288319db22eeb0beeed71261dc0673d6ef
2014-03-04 16:53:39 -08:00
Tom Finegan
23cdb09fd2 mkvmuxer: Silence MSVC warning that suggests making code non-portable.
Change-Id: I19bfa107bf01b1e10ac5a43040d409f4d620f4a7
2014-03-04 16:50:34 -08:00
Tom Finegan
8ae2137637 mkvparser: Silence MSVC warning that suggests making code non-portable.
Change-Id: Ia8b4cd39711105a5b3462b512160f9250e8a5966
2014-02-25 09:36:32 -08:00
Tom Finegan
7952ce8f78 Merge "mkvparser: Fix unused variable warnings when NDEBUG is defined." 2014-02-05 20:56:22 -08:00
Tom Finegan
d58f55542f mkvparser: Fix unused variable warnings when NDEBUG is defined.
Change-Id: I98b1121768e5650c2184acbf35636a15e9241148
2014-02-05 20:44:29 -08:00
Tom Finegan
a0c85b1e46 mkvparser/sample: Fix incorrect printf format specifiers.
Change-Id: I8b61f429f7bb1da7b3def612f6413895f8cb945d
2014-02-05 18:51:17 -08:00
Tom Finegan
4600f5b4a2 Merge "Fix mingw build." 2014-01-24 11:13:56 -08:00
Tom Finegan
a142b15ada Fix mingw build.
Change-Id: Iec913e0cf5849bec459e98df59b0e0bd8e02965b
2014-01-23 22:31:42 -08:00
Tom Finegan
4a3f5c9f99 Merge "mkvparser: Add basic cues walking to sample." 2014-01-23 22:29:12 -08:00
Tom Finegan
84f2156ca1 Merge "mkvmuxer: Add DiscardPadding support." 2014-01-23 15:34:12 -08:00
Tom Finegan
5440f20071 mkvparser: Add basic cues walking to sample.
Change-Id: Ia90e760f04083fa60b44f4d372e118474fc59fee
2014-01-23 15:31:18 -08:00
Tom Finegan
5c14a3f035 mkvparser/mkvreader/sample: CRLF -> LF
Change-Id: Id4a5bea411d104289548b276d0e996352cc816b1
2014-01-23 10:57:06 -08:00
Tom Finegan
71a097fb12 mkvparser sample: clang-formatify
Exception asterisk placement, which was left as before to match the rest of
libwebm.

Change-Id: I3947acc936cca68df72a5bcd8dec17ed40658ba6
2014-01-23 10:52:46 -08:00
Tom Finegan
cd6f7bff4b mkvmuxer: Add DiscardPadding support.
Also a bit of refactoring to remove some duplicate code.

Change-Id: Ia3d17461ae5f6275534e06c31f348bdfc4bba169
2014-01-22 23:26:26 -08:00
Tom Finegan
327e8ab617 Minor clean up: msvc warnings/include order/comment text.
Change-Id: I2b54abcb9f535715d8713930942447c0b0f5f862
2014-01-22 14:03:40 -08:00
Tom Finegan
796c90798a Merge "sample_muxer: Silence MSVC warning." 2014-01-16 13:01:54 -08:00
Sergey Ulanov
0f7815b036 Add license header in sample_muxer_metadata.cc.
This is required by the checklicenses.py script in chromium.

Change-Id: Ice6155b1332adcbda74532e558438083212e1511
2014-01-16 11:31:13 -08:00
Tom Finegan
ccb7fa9c73 sample_muxer: Silence MSVC warning.
Disable C4996; A warning that encourages users to make their code
require the "secure" variant of functions like tmpnam(). Doing so
just happens to make the resulting code require the MSVC runtime.

Change-Id: I0329ce3aa93da060110d24a4bc7f48a7f9c87227
2014-01-15 15:00:59 -08:00
Tom Finegan
4ec1e5cae5 Merge "mkvmuxer: Fix warnings." 2014-01-15 14:36:06 -08:00
Tom Finegan
849093f84f mkvmuxer: CRLF->LF webmids.h.
Match the other muxer sources. Also fix declaration order
of elements in the track grouping.

Change-Id: I06fdb98eb42815af96e80e33379ef73d41b470b3
2014-01-15 12:37:15 -08:00
Tom Finegan
32e1556e68 mkvmuxer: Fix warnings.
Remove useless spam from build output.

Change-Id: Iae200d32cda1fc11cd471772725345d0979e97bc
2014-01-15 12:14:27 -08:00
Tom Finegan
5efd6e3c1d mkvmuxer: Add support for VP9 and Opus tracks.
Also make codec ID constants really constant.

Change-Id: I951d25e83ce507afb1ca475e2d5dbfe6402f3d61
2014-01-10 15:03:47 -08:00
Tom Finegan
a6c71c1407 mkvmuxer: Add support for writing CodecDelay and SeekPreRoll elements.
Change-Id: Iad8c671b76c4b97abad58946df7f3c0ebe6cb01b
2014-01-10 11:32:56 -08:00
Tom Finegan
81c1d8415c mkvparser: Add support for CodecDelay, DiscardPadding, and SeekPreRoll elements.
Change-Id: Ic9e6ebcc2ba533f8cc1ab933d0bf55782ccab932
2014-01-08 17:33:03 -08:00
Vignesh Venkatasubramanian
d2f7478148 Initializing last_block_duration_ to zero.
Adding a missing initialization.

Change-Id: Id4223765968745a46653139b2a9f1537102c3618
2013-10-30 11:13:38 -07:00
Vignesh Venkatasubramanian
fd0a65af98 Merge "Fixing a bug in Chapter::Clear" 2013-10-25 11:13:05 -07:00
Vignesh Venkatasubramanian
872cc57de4 Adding set_uid to Chapter Class
Adding set_uid function to the Chapter class. It can be used to
achieve deterministic output from the muxer. For example, for files
with only one segment, track number or track id can be used for
chapter uid.

Change-Id: I2e94c6150e32cb9019a6623af7919acc099aa20d
2013-10-25 09:33:28 -07:00
Vignesh Venkatasubramanian
ddfea3431f Fixing a bug in Chapter::Clear
Replacing a typo'd < with > in Chapter::Clear of mkvmuxer.

Change-Id: I8784d19dbca5a8a62c92ed14e2efa61d96c5375f
2013-10-25 09:12:11 -07:00
Vignesh Venkatasubramanian
4134f6e04e Adding AddLastFrame to Segment
Adding AddLastFrame function to the Segment muxer so that the duration
of the Segment can be accurately calculated given the last Block's duration.
We now provide an AddLastFrame function which will take duration of that block
as a parameter. When this function is used to add the last frame, the duration
of it is taken into account when computing the Segment's duration.

Change-Id: I3e1456299fefa1a4dd6d845c47292951d1ce3ad0
2013-10-25 08:28:23 -07:00
Tom Finegan
25025a5471 Add dependency checks to Makefile.
Avoid unfortunate things like breaking the library because the make file
was not previously checking dependencies.

Change-Id: Iab20c3cfa0d1475dfb5c54127646b351df1c4c50
2013-08-19 19:32:37 -07:00
Tom Finegan
f72dc7b052 Ignore dependency files and build products.
Change-Id: I4e9da395b8e06a696e77389d0bc863b8837eceee
2013-08-19 11:02:23 -07:00
Tom Finegan
c5892de23b Fix mkvmuxer::Track::set_uid().
Modifying const variables doesn't work.

Change-Id: Ie1aa9ce1779002973ec93f808ba5e86c569b9df4
2013-08-19 11:01:49 -07:00
Tom Finegan
15a708e416 Add set_uid() to mkvmuxer::Track.
Allow users of libwebm's MKV muxer to control the Track UID. This,
for example, allows creation of tests that rely on checksum comparisons
to verify output from the library.

Change-Id: I8b052e6dd5af734d76122b2a1b6b16382ffba214
2013-08-16 10:58:17 -07:00
Vignesh Venkatasubramanian
8206558561 Handling chunking_ being set to true on repositioning cues.
CopyAndMoveCuesBeforeClusters should return false (fail gracefully)
if chunking_ is set to true.

Change-Id: Idf4d573e3f15b59c25ee0774a7875e5dfda9c02e
2013-06-27 11:30:17 -07:00
Vignesh Venkatasubramanian
d782edd68e Update Segment size if Cues size changes on repositioning
Files created with Segment::CopyAndMoveCuesBeforeClusters can't be parsed by
libwebm because the Segment size was not updated to account for the change
in Cue size. Fixing that.

Change-Id: I993f63e5c279f131cd39c54bee40163da00b8cbd
2013-06-24 11:55:53 -07:00
Vignesh Venkatasubramanian
4ac7b755f4 Repositing Cues before Clusters
A whole new approach to repositioning Cues before Clusters. This
patchset adds a new function CopyAndMoveCuesBeforeClusters to the
Segment class. This function should be called after
Segment::Finalize() to obtain a copy of the same output file with
Cues positioned before the Clusters.

Removing everything else that was added to accomplish the same in
the previous few commits.

Also, adding std:: qualifier to one of the variables in
sample_muxer_metadata which was missed accidentally in the previous
commit.

Change-Id: I2810d06a6251325add2f5e54d32d1da6e2fe143f
2013-06-14 13:01:48 -07:00
Vignesh Venkatasubramanian
09dd90fcc7 Fully qualifiying usage of std::string
Replacing "using std::string" with fully qualified namespace on
each occurance of string in sample_muxer_metadata.cc and
webvttparser.cc.

Also fixing a formatting nit in mkvwriteeofreader.cpp

Change-Id: Icf713f9e489fbdc9af14e83d0cb7ba2e89e65ab4
2013-06-12 11:23:35 -07:00
Vignesh Venkatasubramanian
54ca052b1c Changing IMkvReadableWriter to IMkvWriteEOFReader
Changing the IMkvReadableWriter interface to IMkvWriteEOFReader.
Also changing the default implementation.

Change-Id: Id37ffd7ef0af2ff7a392fb4fb0b1b134664ab20f
2013-06-11 15:11:18 -07:00
Vignesh Venkatasubramanian
74e5f0fa1d Adding mkvreadablewriter
Adding mkvreadablewriter files which was missed from previous commit.

Change-Id: I84363ca897ebe758a42538c179ad60c2adfe9247
2013-06-03 14:26:20 -07:00
Vignesh Venkatasubramanian
9b42d039ad Support for placing Cues before Clusters
Adding support for placing Cues element before the Cluster element. We
recompute the new offsets using a recursive algorithm and update the Cues and
Seek Heads with the updates offsets.

Change-Id: I038f1a403b1defa853b9026bd3e48f4ad1006866
2013-06-03 10:27:27 -07:00
Vignesh Venkatasubramanian
3f7681d11e Merge "Fixing mistyped element name in mkvmuxerutil" 2013-05-20 17:11:11 -07:00
Vignesh Venkatasubramanian
7a64466954 Fixing mistyped element name in mkvmuxerutil
Replacing correct element name in mkvmuxerutil that was mistyped
in a previous commit.

Change-Id: Ic34f544aeeb124f0950c3f45e7b638d4616f8b86
2013-05-20 16:46:33 -07:00
Vignesh Venkatasubramanian
05912e8a96 Merge "Elements and functions to support BlockAdditional" 2013-05-07 14:17:43 -07:00
Patrik2 Carlsson
a9f43fe8e7 mkvparser: Get frame default duration
Track::GetDefaultDuration is implemented as an alternative
to VideoTrack::GetFrameRate which seems to be deprecated.

Change-Id: I2c7a6d56a232125b8632d87eab75b9600c5451e1
2013-05-02 16:04:34 +02:00
Vignesh Venkatasubramanian
5af56bb9ee Elements and functions to support BlockAdditional
Adding elements and functions to support muxing of BlockAdditional element.
This is required for supporting muxing of streams with Alpha Channel (where the
Alpha data goes into BlockAdditional). Detailed design doc of Alpha Channel can
be found here: http://goo.gl/wCP1y

Change-Id: Idac144d9588de16685734850585ab7115ddd08a4
2013-04-24 16:16:14 -07:00
Frank Galligan
64cee42b85 libwebm: Remove STL dependency from Android build.
Change-Id: Id2f378f2fa8350aae97394bd8b21918cff4d179a
2013-04-15 10:24:34 -07:00
Frank Galligan
d5cb6c7fa4 libwebm: Fix random number generation on Android.
Change-Id: I593561128aaeb5806f8f015e2de3b4c9aa4411fc
2013-04-15 09:27:34 -07:00
Frank Galligan
252bd24950 libwebm: Update Android build
- Change to libwebm.
- Add muxer support.
- Remove sample app.

Change-Id: I39c31ecbff573f86214e85b3ac08e0dcdfe22ae2
2013-04-15 09:13:07 -07:00
Michael Szal
9cb9ee4efa Removed IsOpen because it should not have been there.
Change-Id: I4d5149de362e50a8f15ebfd382e39218ca2ca560
2013-03-29 11:44:28 -07:00
Patrik Carlsson
3af8d02ca1 mkvparser: support seek for generic tracks (subtitles)
To support seek in generic tracks with subtitles the audio track
implementation of seek is made generic and inherited by audio track.

Change-Id: Ic88d2e859d077a1054b2af7d7680cfddfba8a589
2013-02-28 15:47:04 +01:00
Patrik Carlsson
0d5b3fc5ae mkvparser: add support for compression elements
ContentCompression elements are now parsed.

Change-Id: I9a67ae444ed929e49c7ea223a16c13c9d16a4c13
2013-02-28 15:46:58 +01:00
Patrik Carlsson
3980cf4159 mkvparser: read track language information
Track::GetLanguageAsUTF8 is implemented to allow the user to
choose between available audio and subtitle tracks.

Change-Id: I5ec9b1c1c00182da759681ba486cbace46e9b63f
2013-02-27 15:40:33 +01:00
Matthew Heaney
1274be1184 libwebm: fixed compilation error
Change-Id: I2dfa93f3a2470e016ca905caee33c3dceb789b57
2013-01-31 14:13:33 -08:00
Matthew Heaney
43178b4c9a libwebm: fixed rand() on windows
Change-Id: Ie17445072f10f91bdaabfba74a1be58764d78b94
2013-01-24 17:29:23 -08:00
Matthew Heaney
8376a8e9d7 mkvparser: liberalize parsing of bad elements
Normally, if a sub-element of a cluster reports a size
that lies beyond the end of its enclosing cluster, we
would treat this as a malformed stream and immediately
terminate the parse.

However, if the sub-element is not a simple block or block
group, we would ignore the (sub)element anyway, so there
doesn't appear to be any harm in just concontinuing to
ignore the (sub)element, and treating this case as if
we had reached the end-of-cluster in the normal way.

Change-Id: I16c0a44f7458823ed579612d917b09ee08a8d90a
2013-01-10 19:24:21 -08:00
David Schalig
2b09f9b53a mkvparser: ignore 0-size elements in TrackEntry
ParseTrackEntry handled MKVs with 0-sized EBML elements
as malformed. Relaxing this and allow empty elements to allow
parsing such MKV content.

Change-Id: I7e430e9b2d177df7fe1e656546f63ee8673e784e
2012-12-11 17:08:22 +09:00
Matthew Heaney
28222b4927 Add support for WebVTT cue identifier line
Modified the mkvmuxer to write the ChapterStringUID
sub-element of the Chapter Atom element.

Modified the mkvparser to read the ChapterStringUID
sub-element of the chapter atom.

Modified the vttdemux app to write the Cue Identifier
line of the WebVTT cue.

Change-Id: I06fe386f44897ada3fe10cbf89096df104dcf779
2012-11-13 12:44:06 -08:00
Matthew Heaney
0fcf5e5a40 Merge "vttdemux: add support for WebVTT chapters" 2012-11-13 09:38:29 -08:00
Matthew Heaney
c26db03d5a vttdemux: add support for WebVTT chapters
Change-Id: If5e12ff7057ce4217907ef91d493e1bcd8a72656
2012-11-12 11:52:15 -08:00
Frank Galligan
baefebcf1c libwebm: Fix BlockNumber on CuePoint
- libwebm was writing the BlockNumber of the next Block instead
  of the Block that was just written.

Change-Id: I344800fcea919a82d7f0a04a54cf510be3851ec6
2012-11-12 08:35:39 -08:00
Matthew Heaney
386928d8b8 mkvparser: add missing definitions
Change-Id: I043a6d974bdf146a8726d090722159943eb20752
2012-11-08 18:12:30 -08:00
Matthew Heaney
50ee255b8c mkvparser: add support for MKV chapters
Change-Id: I2404b6886ed592fe505ee973bf05c769a9d134b1
2012-11-02 14:42:40 -07:00
Matthew Heaney
ad54bfb572 sample_muxer: added support for WebVTT chapters
Change-Id: Ic5ab8097c0981ef300eadc4a3c151f63b2aad81d
2012-11-02 14:20:43 -07:00
Matthew Heaney
c99838a5fe Merge "mkvmuxer: add support for WebVTT chapters" 2012-10-31 18:03:59 -07:00
Matthew Heaney
2c5836837e mkvmuxer: add support for WebVTT chapters
Change-Id: I469ce3bd79a9b50b82e00ac8c63fc3d1db220887
2012-10-30 17:07:38 -07:00
Frank Galligan
50afbea946 muxer: Add support to force Cluster placement.
Change-Id: I7d4653561ca760885ba6926825ba6b80cdbea8ab
2012-10-29 09:24:41 -07:00
Matthew Heaney
25ee621061 mkvmuxer: add MakeUID utility function
Change-Id: I3fb57438767ddcc8f9e17c050d494f48ff203e58
2012-10-22 16:50:48 -07:00
Matthew Heaney
ac238c0c5c webvttparser: check intermediate values while parsing int
Change-Id: I145529097246f75c27ff2d29cf091416ba1c437d
2012-10-16 11:32:42 -07:00
Matthew Heaney
4a5141344e vttdemux: initial revision
vttdemux is a tool for demuxing a webm file containing
WebVTT metadata tracks, extracting the embedded metadata
from each track and storing it as a standalone WebVTT file.

Change-Id: I8897b3dc502c49c92f5b79925939baa5a9490aaa
2012-10-12 11:00:24 -07:00
Matthew Heaney
2fc496a0d6 mkvparser: create generic track objects
Formerly, it was only possible to create instances of
the Track subclasses, VideoTrack and AudioTrack.  However,
we now populate WebM files with WebVTT metadata blocks,
so we must allow for a third kind of track object.

We now enable instances of type Track to be created,
by providing a new factory function, Track::Create, and
making all Track methods non-pure and with a generic
implementation.

Change-Id: I7d4c965eb566b9fc2f5ceefe1d43723cf8c1e5f0
2012-10-10 16:51:21 -07:00
Matthew Heaney
cb8899a920 sample_muxer: clean-up to conform to style guide
Change-Id: I77a4657d71359777a8f55f40346014f90051e02d
2012-10-08 12:52:55 -07:00
Matthew Heaney
49078292b4 webvttparser: added LineReader class
Previously the Parser class had an internal function to parse
the character stream into separate lines.  This functionality
was separated out into its own class, LineReader, in order
to make this functionality available to clients too.

Change-Id: Ic5a1b0b73d7a253cf21cb6b4804b4941fd69c8ab
2012-10-02 18:14:51 -07:00
Matthew Heaney
4f494f6dd4 mkvparser: implemented BlockGroup::GetDuration method
Change-Id: Ib0106df3823c29e45a8fe59669c0fa65dd13a123
2012-09-28 14:55:24 -07:00
Matthew Heaney
7ef225de9f sample_muxer: added WebVTT support
Change-Id: If72d31ca4828adf39e4637003979a314e5dda98e
2012-09-28 10:38:19 -07:00
Frank Galligan
8f0c3333d1 Merge "mkvparser: Version 1.0.0.26 mkvmuxer: Version 0.2.0.0" 2012-09-27 10:06:58 -07:00
Frank Galligan
bf664baf05 mkvparser: Version 1.0.0.26 mkvmuxer: Version 0.2.0.0
Change-Id: I6875b1c10adea41c45762d82b7dd2f9551f5b7ca
2012-09-27 09:56:24 -07:00
James Zern
232bae0d50 Merge "Added a rule to the Makefile to build libwebm as a shared library." 2012-09-26 13:37:17 -07:00
Michael Szal
69c9348f07 Added a rule to the Makefile to build libwebm as a shared
library.

I'm building two different object files now: the ones for
libwebm.a are compiled normally (*_a.o), and the ones for
libwebm.so are compiled with -fPIC and linked with -shared
(*_so.o).

Change-Id: I76471ab225a006c7e169bc0d69df9a0731ff6681
2012-09-26 13:15:10 -07:00
Matthew Heaney
711af0c505 mkvmuxer: add operations for muxing metadata
Change-Id: Ia17166ee9133b4841f7d206aa7d5ec81f800e994
2012-09-24 12:13:45 -07:00
Matthew Heaney
38173f9d49 add operation to add generic track
Change-Id: I34e4ab14c0a5b022b77b98d9403125550024e730
2012-09-21 16:37:30 -07:00
Frank Galligan
21a2bd14c7 Make AddCuePoint function public.
Change-Id: I08df2b604185d6ae1d63eb360e68e84efa2cebfa
2012-09-21 16:21:03 -07:00
Frank Galligan
9ec562f72d Add Track number to AddCuePoint function.
Change-Id: I67fd8db3d436f8931f5d50deeb1f1d41cfdc0836
2012-09-21 15:42:57 -07:00
Frank Galligan
e6e2b6b387 Merge "Fix set_writing_app." 2012-09-21 14:08:43 -07:00
Frank Galligan
a2ca300513 Merge "mkvmuxer: default track_num to 0 in AddTrack" 2012-09-21 14:08:08 -07:00
Frank Galligan
6cf00207c0 Fix set_writing_app.
Change-Id: Idbb0522b10184072802be710088f0ec0bf008277
2012-09-21 12:20:43 -07:00
Frank Galligan
4df02ce68b libwebm: Add support for setting muxing app.
Change-Id: I78f4d08142aeeaacf5f9c175bab6a4993b917b1b
2012-09-21 12:17:03 -07:00
Matthew Heaney
4ffb162798 mkvmuxer: default track_num to 0 in AddTrack
Change-Id: I484cb56df7be7677a821db262c75cf8bdf1d30af
2012-09-21 11:55:47 -07:00
Matthew Heaney
76d9cf9cf4 mkvmuxer: handle large gaps in frame timestamps
Change-Id: If223a03cc37f2f373893c914e417475f62949717
2012-09-20 14:58:45 -07:00
Frank Galligan
20f64ff979 Merge "Fix incremental parsing in CreateInstance" 2012-09-14 11:18:27 -07:00
Frank Galligan
537da82f37 Fix incremental parsing in CreateInstance
- Segment::CreateInstance was treating the available data as EOF
  and returning errors.
- Added a check for potential underflow if the segment was not the
  first element after the EBML header.

Change-Id: I481bf0eea71eeb3def3bf54ec251be0b2ae13536
2012-09-14 11:05:18 -07:00
Matthew Heaney
db20aaa2b1 mkvmuxer: refactored code that creates a new cluster
Change-Id: I5db03b0e1ea23f45820dd47b7be9e4b0422f3e6a
2012-09-14 10:17:09 -07:00
Matthew Heaney
c9e284b9e7 refactor code to make a new cluster
Change-Id: Ifa7938134494e3524d6479bd026aea6d1b309d52
2012-09-13 10:15:59 -07:00
Matthew Heaney
07ac1947f0 Change return type of Segment::WriteFramesAll()
Change-Id: I7fb45f1779c384bcc1cdea507f1f2f51c28dd827
2012-09-12 10:29:40 -07:00
Matthew Heaney
0edf087bbb Refactor Cluster::AddFrame member function
Change-Id: Ibff460918243647eb76785508bb50490bc1d8561
2012-09-11 14:58:56 -07:00
Matthew Heaney
c425e965aa add operation to write metadata block
Change-Id: I08f6c7f71dbc9b0d9ce15c08cf288f4918b2c22a
2012-09-05 15:44:45 -07:00
Matthew Heaney
ed6282b2d6 webvttparser more closely conforms to style rules
A few adjustments we made such that the webvttparser
now conforms more closely to the Google C++ style guide.

Change-Id: Iefb2242678ceea6ab5b9daa3a046980deb6cd91c
2012-08-30 15:24:20 -07:00
Matthew Heaney
282a67599c added dumpvtt app
Change-Id: I9eba00412bbd05641dafd1a6cfc4656bda8bb8c2
2012-08-23 14:00:57 -07:00
Matthew Heaney
adebb53754 added webvtt parser
Change-Id: Icef6d484e8fe6e2c63dc69ab02b6ab37ffcabbd8
2012-08-16 16:39:07 -07:00
Frank Galligan
a320f5be63 Add CTR encryption.
- Added ContentEncAESSettings, AESSettingsCipherMode,
  AESSettingsCipherInitData elements to the parser and muxer.
- Changed ParseContentEncodingsEntry, ParseContentEncodingEntry,
  and ParseEncryptionEntry to use PasreElementHeader.
- Added ParseContentEncAESSettingsEntry function.
- PS6 removed AESSettingsCipherInitData.
- PS9 Addressed comments, Fixed some LINT issues, and converted
  mkvwriter.h/.cpp to Unix line endings.
- PS10 Addressed comments.

Change-Id: I9d96a0c194f74a6c9bf0001aa0286196e410f07e
2012-07-27 09:34:31 -07:00
Frank Galligan
c4d2b27b7a Add support for DLL configurations.
- Added "Release DLL" which uses /MTd and "Debug DLL" which
  uses /MDd.

Change-Id: Ibdaf58995e5ee94c34d52ece64e2f8f01524e9cd
2012-07-25 08:41:01 -07:00
Frank Galligan
13a90600ea Muxer fix for chunking file names on Linux.
Change-Id: Ica2dbfc7af64a83fc8f08d35196eabf1dd69f2f0
2012-07-12 08:01:55 -07:00
matthewjheaney
478b524df3 version 1.0.0.25
Change-Id: I438d43572f450bb6e151d4a1ede077ff22252d1f
2012-05-30 15:42:33 -04:00
Tom Finegan
010a457bc9 Add Visual Studio 2010 projects and solution.
Change-Id: I6387f1e6d68b05b8f605f155784c1025f85c1a5b
2012-05-30 14:18:23 -04:00
Tom Finegan
47a09523b2 Ignore visual studio 2010 temporary files.
Change-Id: I18d214b5ba032ff71af2fa67e72a92715636513c
2012-05-30 14:18:22 -04:00
Tom Finegan
84bf4a41dc Move build output outside the repository directory.
Change vs2008 output and intermediate directories to:
1. Avoid build output collisions when using vs2008 and vs2010 on the
   same system (makes no difference until subsequent commit adding
   vs2010 support).
2. Keep the tree clean.

Change-Id: Ie819e57421b7df90244eebffc0f5e608bc135930
2012-05-30 14:18:22 -04:00
Tom Finegan
177df33d25 Move the muxer sample source file and project.
They now reside in the same place as the parser sample.

Change-Id: Idb4471ea81a3d91eeeaf1b36053187203de9a21f
2012-05-30 14:18:08 -04:00
Tom Finegan
4fff53441d Remove visual studio 2005 projects and solution.
Change-Id: I1d4d8cffeb8997eee415246753ea3c29c1af45ec
2012-05-30 11:36:31 -04:00
Tom Finegan
ca13a5bae0 Rename sample_muxer.vcproj to sample_muxer_2008.vcproj.
Also update the solution file path to the project.

Change-Id: I7e83b99893bcde5429e6de03772c61369b29d332
2012-05-29 10:55:00 -04:00
Tom Finegan
cb69e608b4 Enable auto CRLF for visual studio project and solution files.
Change-Id: I23ca85442173eec7a144c001080ca8a3b41609f3
2012-05-29 10:45:59 -04:00
Tom Finegan
f6b0408aba Use LF as EoL in visual studio solutions and projects.
Makes files easier to read in gitweb, and prevents conflict with
upcoming .gitattributes change.

Change-Id: I185e496d8df8efb4987bfb848a582f7d0da81fb8
2012-05-29 10:43:40 -04:00
matthewjheaney
9a561ab4dd libwebm: handle negative time for a block
Change-Id: Iafa0254fb1554621b42635cb99d40b2c0177468f
2012-05-11 11:53:23 -04:00
Frank Galligan
0568dd63a6 Memory Leak Fix in Muxer.
- Track language_ and name_ member variables were not properly
  deleted.
- http://code.google.com/p/webm/issues/detail?id=416

Change-Id: Id0da669c347270cd355ad0b5e1e45ebf6415e367
2012-04-17 15:28:28 -04:00
Frank Galligan
56488f73ef Merge "sample_muxer: Fixed bug with outputting audio cues." 2012-03-16 08:06:54 -07:00
Frank Galligan
f270ddaeb8 sample_muxer: Fixed bug with outputting audio cues.
- For muxed content with default settings the cues was getting
  output on the audio track when it should be on the video track
  by default.
- Added check to command line parameter parsing to make sure
  there are enough parameters.
- If Cues are set to output on one type of track the other type
  is now disabled.

Change-Id: I96ef1978dc3f442f34364f6dee6cfb01571c7289
2012-03-16 09:26:28 -04:00
matthewjheaney
041a5c5811 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-13 14:40:17 -04:00
904 changed files with 51395 additions and 16033 deletions

97
.clang-format Normal file
View File

@ -0,0 +1,97 @@
---
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 Normal file
View File

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

24
.gitignore vendored
View File

@ -2,6 +2,7 @@
*.MKV
core
*.a
*.d
*.so*
*.o
*~
@ -10,6 +11,25 @@ core
*.user
*.suo
*.exe
*.webm
/*.webm
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,13 +1,17 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE:= libmkvparser
LOCAL_SRC_FILES:= mkvparser.cpp \
mkvreader.cpp
include $(BUILD_STATIC_LIBRARY)
LOCAL_MODULE:= libwebm
LOCAL_CPPFLAGS:=-D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS
LOCAL_CPPFLAGS+=-D__STDC_LIMIT_MACROS -std=c++11
LOCAL_C_INCLUDES:= $(LOCAL_PATH)
LOCAL_EXPORT_C_INCLUDES:= $(LOCAL_PATH)
include $(CLEAR_VARS)
LOCAL_MODULE:= mkvparser
LOCAL_SRC_FILES:= sample.cpp
LOCAL_STATIC_LIBRARIES:= libmkvparser
include $(BUILD_EXECUTABLE)
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)

436
CMakeLists.txt Normal file
View File

@ -0,0 +1,436 @@
## 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 ()

View File

@ -1,25 +0,0 @@
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

57
Makefile.unix Normal file
View File

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

143
README.libwebm Normal file
View File

@ -0,0 +1,143 @@
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

View File

@ -1,34 +0,0 @@
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

73
build/cxx_flags.cmake Normal file
View File

@ -0,0 +1,73 @@
## 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 ()

23
build/msvc_runtime.cmake Normal file
View File

@ -0,0 +1,23 @@
## 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 ()

26
build/x86-mingw-gcc.cmake Normal file
View File

@ -0,0 +1,26 @@
## 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

@ -0,0 +1,24 @@
## 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_

62
common/common.sh Normal file
View File

@ -0,0 +1,62 @@
#!/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)
}

93
common/file_util.cc Normal file
View File

@ -0,0 +1,93 @@
// 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

44
common/file_util.h Normal file
View File

@ -0,0 +1,44 @@
// 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_

220
common/hdr_util.cc Normal file
View File

@ -0,0 +1,220 @@
// 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

71
common/hdr_util.h Normal file
View File

@ -0,0 +1,71 @@
// 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_

29
common/indent.cc Normal file
View File

@ -0,0 +1,29 @@
/*
* 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

48
common/indent.h Normal file
View File

@ -0,0 +1,48 @@
/*
* 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_

110
common/libwebm_util.cc Normal file
View File

@ -0,0 +1,110 @@
// 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

65
common/libwebm_util.h Normal file
View File

@ -0,0 +1,65 @@
// 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_

43
common/video_frame.cc Normal file
View File

@ -0,0 +1,43 @@
// 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

68
common/video_frame.h Normal file
View File

@ -0,0 +1,68 @@
// 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_

266
common/vp9_header_parser.cc Normal file
View File

@ -0,0 +1,266 @@
// 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

125
common/vp9_header_parser.h Normal file
View File

@ -0,0 +1,125 @@
// 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

@ -0,0 +1,181 @@
// 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();
}

269
common/vp9_level_stats.cc Normal file
View File

@ -0,0 +1,269 @@
// 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

215
common/vp9_level_stats.h Normal file
View File

@ -0,0 +1,215 @@
// 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

@ -0,0 +1,191 @@
// 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();
}

20
common/webm_constants.h Normal file
View File

@ -0,0 +1,20 @@
// 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_

85
common/webm_endian.cc Normal file
View File

@ -0,0 +1,85 @@
// 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

38
common/webm_endian.h Normal file
View File

@ -0,0 +1,38 @@
// 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_

192
common/webmids.h Normal file
View File

@ -0,0 +1,192 @@
// 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_

91
dumpvtt.cc Normal file
View File

@ -0,0 +1,91 @@
// 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);
}
}

15
hdr_util.hpp Normal file
View File

@ -0,0 +1,15 @@
// 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_

207
iosbuild.sh Executable file
View File

@ -0,0 +1,207 @@
#!/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}."

View File

@ -1,37 +0,0 @@

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

View File

@ -1,204 +0,0 @@
<?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>

View File

@ -1,38 +0,0 @@

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

View File

@ -1,209 +0,0 @@
<?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

@ -0,0 +1,158 @@
// 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();
}

217
m2ts/vpxpes2ts.cc Normal file
View File

@ -0,0 +1,217 @@
// 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

45
m2ts/vpxpes2ts.h Normal file
View File

@ -0,0 +1,45 @@
// 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_

33
m2ts/vpxpes2ts_main.cc Normal file
View File

@ -0,0 +1,33 @@
// 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;
}

410
m2ts/vpxpes_parser.cc Normal file
View File

@ -0,0 +1,410 @@
// 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

177
m2ts/vpxpes_parser.h Normal file
View File

@ -0,0 +1,177 @@
// 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_

542
m2ts/webm2pes.cc Normal file
View File

@ -0,0 +1,542 @@
// 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

274
m2ts/webm2pes.h Normal file
View File

@ -0,0 +1,274 @@
// 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_

33
m2ts/webm2pes_main.cc Normal file
View File

@ -0,0 +1,33 @@
// 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;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,841 +1,15 @@
// Copyright (c) 2011 The WebM project authors. All Rights Reserved.
// 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_MKVMUXER_HPP_
#define LIBWEBM_MKVMUXER_HPP_
#ifndef MKVMUXER_HPP
#define MKVMUXER_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 "mkvmuxer/mkvmuxer.h"
#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
#endif // LIBWEBM_MKVMUXER_HPP_

4193
mkvmuxer/mkvmuxer.cc Normal file

File diff suppressed because it is too large Load Diff

1921
mkvmuxer/mkvmuxer.h Normal file

File diff suppressed because it is too large Load Diff

28
mkvmuxer/mkvmuxertypes.h Normal file
View File

@ -0,0 +1,28 @@
// 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_

744
mkvmuxer/mkvmuxerutil.cc Normal file
View File

@ -0,0 +1,744 @@
// 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

112
mkvmuxer/mkvmuxerutil.h Normal file
View File

@ -0,0 +1,112 @@
// 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,94 +1,90 @@
// 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 "mkvwriter.hpp"
#ifdef _MSC_VER
#include <share.h> // for _SH_DENYWR
#endif
#include <new>
namespace mkvmuxer {
MkvWriter::MkvWriter() : file_(NULL) {
}
MkvWriter::~MkvWriter() {
Close();
}
int32 MkvWriter::Write(const void* buffer, uint32 length) {
if (!file_)
return -1;
if (length == 0)
return 0;
if (buffer == NULL)
return -1;
const size_t bytes_written = fwrite(buffer, 1, length, file_);
return (bytes_written == length) ? 0 : -1;
}
bool MkvWriter::Open(const char* filename) {
if (filename == NULL)
return false;
if (file_)
return false;
#ifdef _MSC_VER
file_ = _fsopen(filename, "wb", _SH_DENYWR);
#else
file_ = fopen(filename, "wb");
#endif
if (file_ == NULL)
return false;
return true;
}
void MkvWriter::Close() {
if (file_) {
fclose(file_);
file_ = NULL;
}
}
int64 MkvWriter::Position() const {
if (!file_)
return 0;
#ifdef _MSC_VER
return _ftelli64(file_);
#else
return ftell(file_);
#endif
}
int32 MkvWriter::Position(int64 position) {
if (!file_)
return -1;
#ifdef _MSC_VER
return _fseeki64(file_, position, SEEK_SET);
#else
return fseek(file_, position, SEEK_SET);
#endif
}
bool MkvWriter::Seekable() const {
return true;
}
void MkvWriter::ElementStartNotify(uint64, int64) {
}
} // namespace mkvmuxer
// 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/mkvwriter.h"
#include <sys/types.h>
#ifdef _MSC_VER
#include <share.h> // for _SH_DENYWR
#endif
namespace mkvmuxer {
MkvWriter::MkvWriter() : file_(NULL), writer_owns_file_(true) {}
MkvWriter::MkvWriter(FILE* fp) : file_(fp), writer_owns_file_(false) {}
MkvWriter::~MkvWriter() { Close(); }
int32 MkvWriter::Write(const void* buffer, uint32 length) {
if (!file_)
return -1;
if (length == 0)
return 0;
if (buffer == NULL)
return -1;
const size_t bytes_written = fwrite(buffer, 1, length, file_);
return (bytes_written == length) ? 0 : -1;
}
bool MkvWriter::Open(const char* filename) {
if (filename == NULL)
return false;
if (file_)
return false;
#ifdef _MSC_VER
file_ = _fsopen(filename, "wb", _SH_DENYWR);
#else
file_ = fopen(filename, "wb");
#endif
if (file_ == NULL)
return false;
return true;
}
void MkvWriter::Close() {
if (file_ && writer_owns_file_) {
fclose(file_);
}
file_ = NULL;
}
int64 MkvWriter::Position() const {
if (!file_)
return 0;
#ifdef _MSC_VER
return _ftelli64(file_);
#else
return ftell(file_);
#endif
}
int32 MkvWriter::Position(int64 position) {
if (!file_)
return -1;
#ifdef _MSC_VER
return _fseeki64(file_, position, SEEK_SET);
#else
return fseeko(file_, static_cast<off_t>(position), SEEK_SET);
#endif
}
bool MkvWriter::Seekable() const { return true; }
void MkvWriter::ElementStartNotify(uint64, int64) {}
} // namespace mkvmuxer

51
mkvmuxer/mkvwriter.h Normal file
View File

@ -0,0 +1,51 @@
// 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_

785
mkvmuxer_sample.cc Normal file
View File

@ -0,0 +1,785 @@
// 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,29 +1,15 @@
// 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.
#ifndef MKVMUXERTYPES_HPP
#define MKVMUXERTYPES_HPP
// Copied from Chromium basictypes.h
// A macro to disallow the copy constructor and operator= functions
// This should be used in the private: declarations for a class
#define LIBWEBM_DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&); \
void operator=(const TypeName&)
namespace mkvmuxer {
typedef unsigned char uint8;
typedef int int32;
typedef unsigned int uint32;
typedef long long int64;
typedef unsigned long long uint64;
} //end namespace mkvmuxer
#endif // MKVMUXERTYPES_HPP
// 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_MKVMUXERTYPES_HPP_
#define LIBWEBM_MKVMUXERTYPES_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 "mkvmuxer/mkvmuxertypes.h"
#endif // LIBWEBM_MKVMUXERTYPES_HPP_

View File

@ -1,390 +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 "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,82 +1,18 @@
// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
// 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_MKVMUXERUTIL_HPP_
#define LIBWEBM_MKVMUXERUTIL_HPP_
#ifndef MKVMUXERUTIL_HPP
#define MKVMUXERUTIL_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 "mkvmuxer/mkvmuxerutil.h"
#include "mkvmuxertypes.hpp"
using mkvmuxer::EbmlElementSize;
using mkvmuxer::EbmlMasterElementSize;
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
#endif // LIBWEBM_MKVMUXERUTIL_HPP_

File diff suppressed because it is too large Load Diff

View File

@ -1,896 +1,15 @@
// 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_HPP
#define 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
// 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_MKVPARSER_HPP_
#define LIBWEBM_MKVPARSER_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 "mkvparser/mkvparser.h"
#endif // LIBWEBM_MKVPARSER_HPP_

8049
mkvparser/mkvparser.cc Normal file

File diff suppressed because it is too large Load Diff

1145
mkvparser/mkvparser.h Normal file

File diff suppressed because it is too large Load Diff

133
mkvparser/mkvreader.cc Normal file
View File

@ -0,0 +1,133 @@
// 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

45
mkvparser/mkvreader.h Normal file
View File

@ -0,0 +1,45 @@
// 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_

459
mkvparser_sample.cc Normal file
View File

@ -0,0 +1,459 @@
// 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;
}

View File

@ -1,128 +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 "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,39 +1,15 @@
// 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 MKVREADER_HPP
#define 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
// 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_MKVREADER_HPP_
#define LIBWEBM_MKVREADER_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 "mkvparser/mkvreader.h"
#endif // LIBWEBM_MKVREADER_HPP_

View File

@ -1,49 +1,15 @@
// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
#ifndef MKVWRITER_HPP
#define MKVWRITER_HPP
#include <stdio.h>
#include "mkvmuxer.hpp"
#include "mkvmuxertypes.hpp"
namespace mkvmuxer {
// Default implementation of the IMkvWriter interface on Windows.
class MkvWriter : public IMkvWriter {
public:
MkvWriter();
virtual ~MkvWriter();
// IMkvWriter interface
virtual int64 Position() const;
virtual int32 Position(int64 position);
virtual bool Seekable() const;
virtual int32 Write(const void* buffer, uint32 length);
virtual void ElementStartNotify(uint64 element_id, int64 position);
// Creates and opens a file for writing. |filename| is the name of the file
// to open. This function will overwrite the contents of |filename|. Returns
// true on success.
bool Open(const char* filename);
// Closes an opened file.
void Close();
private:
// File handle to output file.
FILE* file_;
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(MkvWriter);
};
} //end namespace mkvmuxer
#endif // MKVWRITER_HPP
// 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_MKVWRITER_HPP_
#define LIBWEBM_MKVWRITER_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 "mkvmuxer/mkvwriter.h"
#endif // LIBWEBM_MKVWRITER_HPP_

View File

@ -1,317 +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 "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;
}

View File

@ -1,194 +0,0 @@
<?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>

View File

@ -1,193 +0,0 @@
<?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

@ -1,397 +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 <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

@ -1,197 +0,0 @@
<?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>

391
sample_muxer_metadata.cc Normal file
View File

@ -0,0 +1,391 @@
// 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);
}

137
sample_muxer_metadata.h Normal file
View File

@ -0,0 +1,137 @@
// 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

1010
testing/mkvmuxer_tests.cc Normal file

File diff suppressed because it is too large Load Diff

823
testing/mkvparser_tests.cc Normal file
View File

@ -0,0 +1,823 @@
// 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();
}

215
testing/test_util.cc Normal file
View File

@ -0,0 +1,215 @@
// 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

88
testing/test_util.h Normal file
View File

@ -0,0 +1,88 @@
// 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.

BIN
testing/testdata/chapters.webm vendored Normal file

Binary file not shown.

BIN
testing/testdata/colour.webm vendored Normal file

Binary file not shown.

Binary file not shown.

BIN
testing/testdata/discard_padding.webm vendored Normal file

Binary file not shown.

BIN
testing/testdata/estimate_duration.webm vendored Normal file

Binary file not shown.

Binary file not shown.

BIN
testing/testdata/force_new_cluster.webm vendored Normal file

Binary file not shown.

24
testing/testdata/invalid/README.libwebm vendored Normal file
View File

@ -0,0 +1,24 @@
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.

Binary file not shown.

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