mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-24 11:16:34 +00:00
add opus/webm encoding (#22923)
This commit is contained in:
parent
e8ca96008f
commit
def7ede895
@ -171,7 +171,7 @@ extern "C" {
|
||||
#define OPUS_GET_IN_DTX_REQUEST 4049
|
||||
|
||||
/** Defines for the presence of extended APIs. */
|
||||
#define OPUS_HAVE_OPUS_PROJECTION_H
|
||||
// #define OPUS_HAVE_OPUS_PROJECTION_H
|
||||
|
||||
/* Macros to trigger compilation errors when the wrong types are provided to a CTL */
|
||||
#define __opus_check_int(x) (((void)((x) == (opus_int32)0)), (opus_int32)(x))
|
||||
|
35
lib/lib_audio/ESP8266Audio/src/libwebm/.clang-format
Normal file
35
lib/lib_audio/ESP8266Audio/src/libwebm/.clang-format
Normal file
@ -0,0 +1,35 @@
|
||||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: Google
|
||||
AlignTrailingComments: false
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
|
||||
# A separate 'Other libraries' grouping is added before libwebm's headers for
|
||||
# gtest and gmock includes. This is based on the suggested grouping in the
|
||||
# Google C++ Style Guide:
|
||||
# https://google.github.io/styleguide/cppguide.html#Names_and_Order_of_Includes
|
||||
# The other categories come from `clang-format-14 --dump-config --style=Google`.
|
||||
# See the clang-format documentation for more information on this option:
|
||||
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html#includecategories
|
||||
IncludeCategories:
|
||||
- Regex: '^<ext/.*\.h>'
|
||||
Priority: 2
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '^<.*\.h>'
|
||||
Priority: 1
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '^<.*'
|
||||
Priority: 2
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '^((<|")(gtest|gmock)/)'
|
||||
Priority: 3
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '.*'
|
||||
Priority: 4
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
6
lib/lib_audio/ESP8266Audio/src/libwebm/.gitattributes
vendored
Normal file
6
lib/lib_audio/ESP8266Audio/src/libwebm/.gitattributes
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
*.sln eol=crlf
|
||||
*.vcproj eol=crlf
|
||||
*.vsprops eol=crlf
|
||||
*.vcxproj eol=crlf
|
||||
*.mkv -text -diff
|
||||
*.webm -text -diff
|
36
lib/lib_audio/ESP8266Audio/src/libwebm/.gitignore
vendored
Normal file
36
lib/lib_audio/ESP8266Audio/src/libwebm/.gitignore
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
*.MKV
|
||||
*.a
|
||||
*.cmake
|
||||
*.d
|
||||
*.exe
|
||||
*.mkv
|
||||
*.ncb
|
||||
*.o
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.so*
|
||||
*.suo
|
||||
*.swp
|
||||
*.user
|
||||
*~
|
||||
.vscode
|
||||
/*.webm
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
Debug
|
||||
Makefile
|
||||
Release
|
||||
core
|
||||
dumpvtt
|
||||
ipch
|
||||
mkvmuxer_sample
|
||||
mkvmuxer_tests
|
||||
mkvparser_sample
|
||||
mkvparser_tests
|
||||
vp9_header_parser_tests
|
||||
vp9_level_stats_tests
|
||||
vttdemux
|
||||
webm2pes
|
||||
webm2pes_tests
|
||||
webm2ts
|
||||
webm_info
|
6
lib/lib_audio/ESP8266Audio/src/libwebm/.mailmap
Normal file
6
lib/lib_audio/ESP8266Audio/src/libwebm/.mailmap
Normal file
@ -0,0 +1,6 @@
|
||||
Hui Su <huisu@google.com>
|
||||
Matthew Heaney <matthewjheaney@google.com>
|
||||
Neil Birkbeck <birkbeck@google.com>
|
||||
Patrik Carlsson <patrik2.carlsson@sonymobile.com>
|
||||
Roberto Alanis Baez <alanisbaez@google.com>
|
||||
Tom Finegan <tomfinegan@google.com> <tomfinegan@chromium.org>
|
441
lib/lib_audio/ESP8266Audio/src/libwebm/.pylintrc
Normal file
441
lib/lib_audio/ESP8266Audio/src/libwebm/.pylintrc
Normal file
@ -0,0 +1,441 @@
|
||||
# This Pylint rcfile contains a best-effort configuration to uphold the
|
||||
# best-practices and style described in the Google Python style guide:
|
||||
# https://google.github.io/styleguide/pyguide.html
|
||||
#
|
||||
# Its canonical open-source location is:
|
||||
# https://google.github.io/styleguide/pylintrc
|
||||
|
||||
[MASTER]
|
||||
|
||||
# Files or directories to be skipped. They should be base names, not paths.
|
||||
ignore=third_party
|
||||
|
||||
# Files or directories matching the regex patterns are skipped. The regex
|
||||
# matches against base names, not paths.
|
||||
ignore-patterns=
|
||||
|
||||
# Pickle collected data for later comparisons.
|
||||
persistent=no
|
||||
|
||||
# List of plugins (as comma separated values of python modules names) to load,
|
||||
# usually to register additional checkers.
|
||||
load-plugins=
|
||||
|
||||
# Use multiple processes to speed up Pylint.
|
||||
jobs=4
|
||||
|
||||
# Allow loading of arbitrary C extensions. Extensions are imported into the
|
||||
# active Python interpreter and may run arbitrary code.
|
||||
unsafe-load-any-extension=no
|
||||
|
||||
|
||||
[MESSAGES CONTROL]
|
||||
|
||||
# Only show warnings with the listed confidence levels. Leave empty to show
|
||||
# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
|
||||
confidence=
|
||||
|
||||
# Enable the message, report, category or checker with the given id(s). You can
|
||||
# either give multiple identifier separated by comma (,) or put this option
|
||||
# multiple time (only on the command line, not in the configuration file where
|
||||
# it should appear only once). See also the "--disable" option for examples.
|
||||
#enable=
|
||||
|
||||
# Disable the message, report, category or checker with the given id(s). You
|
||||
# can either give multiple identifiers separated by comma (,) or put this
|
||||
# option multiple times (only on the command line, not in the configuration
|
||||
# file where it should appear only once).You can also use "--disable=all" to
|
||||
# disable everything first and then reenable specific checks. For example, if
|
||||
# you want to run only the similarities checker, you can use "--disable=all
|
||||
# --enable=similarities". If you want to run only the classes checker, but have
|
||||
# no Warning level messages displayed, use"--disable=all --enable=classes
|
||||
# --disable=W"
|
||||
disable=abstract-method,
|
||||
apply-builtin,
|
||||
arguments-differ,
|
||||
attribute-defined-outside-init,
|
||||
backtick,
|
||||
bad-option-value,
|
||||
basestring-builtin,
|
||||
buffer-builtin,
|
||||
c-extension-no-member,
|
||||
consider-using-enumerate,
|
||||
cmp-builtin,
|
||||
cmp-method,
|
||||
coerce-builtin,
|
||||
coerce-method,
|
||||
delslice-method,
|
||||
div-method,
|
||||
duplicate-code,
|
||||
eq-without-hash,
|
||||
execfile-builtin,
|
||||
file-builtin,
|
||||
filter-builtin-not-iterating,
|
||||
fixme,
|
||||
getslice-method,
|
||||
global-statement,
|
||||
hex-method,
|
||||
idiv-method,
|
||||
implicit-str-concat-in-sequence,
|
||||
import-error,
|
||||
import-self,
|
||||
import-star-module-level,
|
||||
inconsistent-return-statements,
|
||||
input-builtin,
|
||||
intern-builtin,
|
||||
invalid-str-codec,
|
||||
locally-disabled,
|
||||
long-builtin,
|
||||
long-suffix,
|
||||
map-builtin-not-iterating,
|
||||
misplaced-comparison-constant,
|
||||
missing-function-docstring,
|
||||
metaclass-assignment,
|
||||
next-method-called,
|
||||
next-method-defined,
|
||||
no-absolute-import,
|
||||
no-else-break,
|
||||
no-else-continue,
|
||||
no-else-raise,
|
||||
no-else-return,
|
||||
no-init, # added
|
||||
no-member,
|
||||
no-name-in-module,
|
||||
no-self-use,
|
||||
nonzero-method,
|
||||
oct-method,
|
||||
old-division,
|
||||
old-ne-operator,
|
||||
old-octal-literal,
|
||||
old-raise-syntax,
|
||||
parameter-unpacking,
|
||||
print-statement,
|
||||
raising-string,
|
||||
range-builtin-not-iterating,
|
||||
raw_input-builtin,
|
||||
rdiv-method,
|
||||
reduce-builtin,
|
||||
relative-import,
|
||||
reload-builtin,
|
||||
round-builtin,
|
||||
setslice-method,
|
||||
signature-differs,
|
||||
standarderror-builtin,
|
||||
suppressed-message,
|
||||
sys-max-int,
|
||||
too-few-public-methods,
|
||||
too-many-ancestors,
|
||||
too-many-arguments,
|
||||
too-many-boolean-expressions,
|
||||
too-many-branches,
|
||||
too-many-instance-attributes,
|
||||
too-many-locals,
|
||||
too-many-nested-blocks,
|
||||
too-many-public-methods,
|
||||
too-many-return-statements,
|
||||
too-many-statements,
|
||||
trailing-newlines,
|
||||
unichr-builtin,
|
||||
unicode-builtin,
|
||||
unnecessary-pass,
|
||||
unpacking-in-except,
|
||||
useless-else-on-loop,
|
||||
useless-object-inheritance,
|
||||
useless-suppression,
|
||||
using-cmp-argument,
|
||||
wrong-import-order,
|
||||
xrange-builtin,
|
||||
zip-builtin-not-iterating,
|
||||
|
||||
|
||||
[REPORTS]
|
||||
|
||||
# Set the output format. Available formats are text, parseable, colorized, msvs
|
||||
# (visual studio) and html. You can also give a reporter class, eg
|
||||
# mypackage.mymodule.MyReporterClass.
|
||||
output-format=text
|
||||
|
||||
# Put messages in a separate file for each module / package specified on the
|
||||
# command line instead of printing them on stdout. Reports (if any) will be
|
||||
# written in a file name "pylint_global.[txt|html]". This option is deprecated
|
||||
# and it will be removed in Pylint 2.0.
|
||||
files-output=no
|
||||
|
||||
# Tells whether to display a full report or only the messages
|
||||
reports=no
|
||||
|
||||
# Python expression which should return a note less than 10 (10 is the highest
|
||||
# note). You have access to the variables errors warning, statement which
|
||||
# respectively contain the number of errors / warnings messages and the total
|
||||
# number of statements analyzed. This is used by the global evaluation report
|
||||
# (RP0004).
|
||||
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
|
||||
|
||||
# Template used to display messages. This is a python new-style format string
|
||||
# used to format the message information. See doc for all details
|
||||
#msg-template=
|
||||
|
||||
|
||||
[BASIC]
|
||||
|
||||
# Good variable names which should always be accepted, separated by a comma
|
||||
good-names=main,_,PRESUBMIT
|
||||
|
||||
# Bad variable names which should always be refused, separated by a comma
|
||||
bad-names=
|
||||
|
||||
# Colon-delimited sets of names that determine each other's naming style when
|
||||
# the name regexes allow several styles.
|
||||
name-group=
|
||||
|
||||
# Include a hint for the correct naming format with invalid-name
|
||||
include-naming-hint=no
|
||||
|
||||
# List of decorators that produce properties, such as abc.abstractproperty. Add
|
||||
# to this list to register other decorators that produce valid properties.
|
||||
property-classes=abc.abstractproperty,cached_property.cached_property,cached_property.threaded_cached_property,cached_property.cached_property_with_ttl,cached_property.threaded_cached_property_with_ttl
|
||||
|
||||
# Regular expression matching correct function names
|
||||
function-rgx=^(?:(?P<exempt>setUp|tearDown|setUpModule|tearDownModule)|(?P<camel_case>_?[A-Z][a-zA-Z0-9]*)|(?P<snake_case>_?[a-z][a-z0-9_]*))$
|
||||
|
||||
# Regular expression matching correct variable names
|
||||
variable-rgx=^[a-z][a-z0-9_]*$
|
||||
|
||||
# Regular expression matching correct constant names
|
||||
const-rgx=^(_?[A-Z][A-Z0-9_]*|__[a-z0-9_]+__|_?[a-z][a-z0-9_]*)$
|
||||
|
||||
# Regular expression matching correct attribute names
|
||||
attr-rgx=^_{0,2}[a-z][a-z0-9_]*$
|
||||
|
||||
# Regular expression matching correct argument names
|
||||
argument-rgx=^[a-z][a-z0-9_]*$
|
||||
|
||||
# Regular expression matching correct class attribute names
|
||||
class-attribute-rgx=^(_?[A-Z][A-Z0-9_]*|__[a-z0-9_]+__|_?[a-z][a-z0-9_]*)$
|
||||
|
||||
# Regular expression matching correct inline iteration names
|
||||
inlinevar-rgx=^[a-z][a-z0-9_]*$
|
||||
|
||||
# Regular expression matching correct class names
|
||||
class-rgx=^_?[A-Z][a-zA-Z0-9]*$
|
||||
|
||||
# Regular expression matching correct module names
|
||||
module-rgx=^(_?[a-z][a-z0-9_]*|__init__)$
|
||||
|
||||
# Regular expression matching correct method names
|
||||
method-rgx=(?x)^(?:(?P<exempt>_[a-z0-9_]+__|runTest|setUp|tearDown|setUpTestCase|tearDownTestCase|setupSelf|tearDownClass|setUpClass|(test|assert)_*[A-Z0-9][a-zA-Z0-9_]*|next)|(?P<camel_case>_{0,2}[A-Z][a-zA-Z0-9_]*)|(?P<snake_case>_{0,2}[a-z][a-z0-9_]*))$
|
||||
|
||||
# Regular expression which should only match function or class names that do
|
||||
# not require a docstring.
|
||||
no-docstring-rgx=(__.*__|main|test.*|.*test|.*Test)$
|
||||
|
||||
# Minimum line length for functions/classes that require docstrings, shorter
|
||||
# ones are exempt.
|
||||
docstring-min-length=10
|
||||
|
||||
|
||||
[TYPECHECK]
|
||||
|
||||
# List of decorators that produce context managers, such as
|
||||
# contextlib.contextmanager. Add to this list to register other decorators that
|
||||
# produce valid context managers.
|
||||
contextmanager-decorators=contextlib.contextmanager,contextlib2.contextmanager
|
||||
|
||||
# Tells whether missing members accessed in mixin class should be ignored. A
|
||||
# mixin class is detected if its name ends with "mixin" (case insensitive).
|
||||
ignore-mixin-members=yes
|
||||
|
||||
# List of module names for which member attributes should not be checked
|
||||
# (useful for modules/projects where namespaces are manipulated during runtime
|
||||
# and thus existing member attributes cannot be deduced by static analysis. It
|
||||
# supports qualified module names, as well as Unix pattern matching.
|
||||
ignored-modules=
|
||||
|
||||
# List of class names for which member attributes should not be checked (useful
|
||||
# for classes with dynamically set attributes). This supports the use of
|
||||
# qualified names.
|
||||
ignored-classes=optparse.Values,thread._local,_thread._local
|
||||
|
||||
# List of members which are set dynamically and missed by pylint inference
|
||||
# system, and so shouldn't trigger E1101 when accessed. Python regular
|
||||
# expressions are accepted.
|
||||
generated-members=
|
||||
|
||||
|
||||
[FORMAT]
|
||||
|
||||
# Maximum number of characters on a single line.
|
||||
max-line-length=80
|
||||
|
||||
# TODO(https://github.com/PyCQA/pylint/issues/3352): Direct pylint to exempt
|
||||
# lines made too long by directives to pytype.
|
||||
|
||||
# Regexp for a line that is allowed to be longer than the limit.
|
||||
ignore-long-lines=(?x)(
|
||||
^\s*(\#\ )?<?https?://\S+>?$|
|
||||
^\s*(from\s+\S+\s+)?import\s+.+$)
|
||||
|
||||
# Allow the body of an if to be on the same line as the test if there is no
|
||||
# else.
|
||||
single-line-if-stmt=yes
|
||||
|
||||
# List of optional constructs for which whitespace checking is disabled. `dict-
|
||||
# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
|
||||
# `trailing-comma` allows a space between comma and closing bracket: (a, ).
|
||||
# `empty-line` allows space-only lines.
|
||||
no-space-check=
|
||||
|
||||
# Maximum number of lines in a module
|
||||
max-module-lines=99999
|
||||
|
||||
# String used as indentation unit. The internal Google style guide mandates 2
|
||||
# spaces. Google's externaly-published style guide says 4, consistent with
|
||||
# PEP 8. Here, we use 2 spaces, for conformity with many open-sourced Google
|
||||
# projects (like TensorFlow).
|
||||
indent-string=' '
|
||||
|
||||
# Number of spaces of indent required inside a hanging or continued line.
|
||||
indent-after-paren=4
|
||||
|
||||
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
|
||||
expected-line-ending-format=
|
||||
|
||||
|
||||
[MISCELLANEOUS]
|
||||
|
||||
# List of note tags to take in consideration, separated by a comma.
|
||||
notes=TODO
|
||||
|
||||
|
||||
[STRING]
|
||||
|
||||
# This flag controls whether inconsistent-quotes generates a warning when the
|
||||
# character used as a quote delimiter is used inconsistently within a module.
|
||||
check-quote-consistency=yes
|
||||
|
||||
|
||||
[VARIABLES]
|
||||
|
||||
# Tells whether we should check for unused import in __init__ files.
|
||||
init-import=no
|
||||
|
||||
# A regular expression matching the name of dummy variables (i.e. expectedly
|
||||
# not used).
|
||||
dummy-variables-rgx=^\*{0,2}(_$|unused_|dummy_)
|
||||
|
||||
# List of additional names supposed to be defined in builtins. Remember that
|
||||
# you should avoid to define new builtins when possible.
|
||||
additional-builtins=
|
||||
|
||||
# List of strings which can identify a callback function by name. A callback
|
||||
# name must start or end with one of those strings.
|
||||
callbacks=cb_,_cb
|
||||
|
||||
# List of qualified module names which can have objects that can redefine
|
||||
# builtins.
|
||||
redefining-builtins-modules=six,six.moves,past.builtins,future.builtins,functools
|
||||
|
||||
|
||||
[LOGGING]
|
||||
|
||||
# Logging modules to check that the string format arguments are in logging
|
||||
# function parameter format
|
||||
logging-modules=logging,absl.logging,tensorflow.io.logging
|
||||
|
||||
|
||||
[SIMILARITIES]
|
||||
|
||||
# Minimum lines number of a similarity.
|
||||
min-similarity-lines=4
|
||||
|
||||
# Ignore comments when computing similarities.
|
||||
ignore-comments=yes
|
||||
|
||||
# Ignore docstrings when computing similarities.
|
||||
ignore-docstrings=yes
|
||||
|
||||
# Ignore imports when computing similarities.
|
||||
ignore-imports=no
|
||||
|
||||
|
||||
[SPELLING]
|
||||
|
||||
# Spelling dictionary name. Available dictionaries: none. To make it working
|
||||
# install python-enchant package.
|
||||
spelling-dict=
|
||||
|
||||
# List of comma separated words that should not be checked.
|
||||
spelling-ignore-words=
|
||||
|
||||
# A path to a file that contains private dictionary; one word per line.
|
||||
spelling-private-dict-file=
|
||||
|
||||
# Tells whether to store unknown words to indicated private dictionary in
|
||||
# --spelling-private-dict-file option instead of raising a message.
|
||||
spelling-store-unknown-words=no
|
||||
|
||||
|
||||
[IMPORTS]
|
||||
|
||||
# Deprecated modules which should not be used, separated by a comma
|
||||
deprecated-modules=regsub,
|
||||
TERMIOS,
|
||||
Bastion,
|
||||
rexec,
|
||||
sets
|
||||
|
||||
# Create a graph of every (i.e. internal and external) dependencies in the
|
||||
# given file (report RP0402 must not be disabled)
|
||||
import-graph=
|
||||
|
||||
# Create a graph of external dependencies in the given file (report RP0402 must
|
||||
# not be disabled)
|
||||
ext-import-graph=
|
||||
|
||||
# Create a graph of internal dependencies in the given file (report RP0402 must
|
||||
# not be disabled)
|
||||
int-import-graph=
|
||||
|
||||
# Force import order to recognize a module as part of the standard
|
||||
# compatibility libraries.
|
||||
known-standard-library=
|
||||
|
||||
# Force import order to recognize a module as part of a third party library.
|
||||
known-third-party=enchant, absl
|
||||
|
||||
# Analyse import fallback blocks. This can be used to support both Python 2 and
|
||||
# 3 compatible code, which means that the block might have code that exists
|
||||
# only in one or another interpreter, leading to false positives when analysed.
|
||||
analyse-fallback-blocks=no
|
||||
|
||||
|
||||
[CLASSES]
|
||||
|
||||
# List of method names used to declare (i.e. assign) instance attributes.
|
||||
defining-attr-methods=__init__,
|
||||
__new__,
|
||||
setUp
|
||||
|
||||
# List of member names, which should be excluded from the protected access
|
||||
# warning.
|
||||
exclude-protected=_asdict,
|
||||
_fields,
|
||||
_replace,
|
||||
_source,
|
||||
_make
|
||||
|
||||
# List of valid names for the first argument in a class method.
|
||||
valid-classmethod-first-arg=cls,
|
||||
class_
|
||||
|
||||
# List of valid names for the first argument in a metaclass class method.
|
||||
valid-metaclass-classmethod-first-arg=mcs
|
||||
|
||||
|
||||
[EXCEPTIONS]
|
||||
|
||||
# Exceptions that will emit a warning when being caught. Defaults to
|
||||
# "Exception"
|
||||
overgeneral-exceptions=StandardError,
|
||||
Exception,
|
||||
BaseException
|
5
lib/lib_audio/ESP8266Audio/src/libwebm/AUTHORS.TXT
Normal file
5
lib/lib_audio/ESP8266Audio/src/libwebm/AUTHORS.TXT
Normal file
@ -0,0 +1,5 @@
|
||||
# Names should be added to this file like so:
|
||||
# Name or Organization <email address>
|
||||
|
||||
Google Inc.
|
||||
Elijah Cirioli <eli.cirioli@gmail.com>
|
41
lib/lib_audio/ESP8266Audio/src/libwebm/CONTRIBUTING.md
Normal file
41
lib/lib_audio/ESP8266Audio/src/libwebm/CONTRIBUTING.md
Normal file
@ -0,0 +1,41 @@
|
||||
# How to Contribute
|
||||
|
||||
We'd love to accept your patches and contributions to this project. There are
|
||||
just a few small guidelines you need to follow.
|
||||
|
||||
## Contributor License Agreement
|
||||
|
||||
Contributions to this project must be accompanied by a Contributor License
|
||||
Agreement. You (or your employer) retain the copyright to your contribution;
|
||||
this simply gives us permission to use and redistribute your contributions as
|
||||
part of the project. Head over to <https://cla.developers.google.com/> to see
|
||||
your current agreements on file or to sign a new one.
|
||||
|
||||
You generally only need to submit a CLA once, so if you've already submitted one
|
||||
(even if it was for a different project), you probably don't need to do it
|
||||
again.
|
||||
|
||||
## Code reviews
|
||||
|
||||
All submissions, including submissions by project members, require review. We
|
||||
use a [Gerrit](https://www.gerritcodereview.com) instance hosted at
|
||||
https://chromium-review.googlesource.com for this purpose. See the
|
||||
[WebM Project page](https://www.webmproject.org/code/contribute/submitting-patches/)
|
||||
for additional details.
|
||||
|
||||
## Code Style
|
||||
|
||||
The C++ code style is based on the
|
||||
[Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html) and
|
||||
`clang-format --style=Google`. `clang-format -i --style=file` can be used to
|
||||
format individual files, it will use the settings from `.clang-format`.
|
||||
|
||||
CMake files are formatted with
|
||||
[cmake-format](https://cmake-format.readthedocs.io/en/latest/). `cmake-format
|
||||
-i` can be used to format individual files, it will use the settings from
|
||||
`.cmake-format.py`.
|
||||
|
||||
## Community Guidelines
|
||||
|
||||
This project follows
|
||||
[Google's Open Source Community Guidelines](https://opensource.google.com/conduct/).
|
30
lib/lib_audio/ESP8266Audio/src/libwebm/LICENSE.TXT
Normal file
30
lib/lib_audio/ESP8266Audio/src/libwebm/LICENSE.TXT
Normal file
@ -0,0 +1,30 @@
|
||||
Copyright (c) 2010, Google Inc. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
* Neither the name of Google nor the names of its contributors may
|
||||
be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
23
lib/lib_audio/ESP8266Audio/src/libwebm/PATENTS.TXT
Normal file
23
lib/lib_audio/ESP8266Audio/src/libwebm/PATENTS.TXT
Normal file
@ -0,0 +1,23 @@
|
||||
Additional IP Rights Grant (Patents)
|
||||
------------------------------------
|
||||
|
||||
"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 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.
|
202
lib/lib_audio/ESP8266Audio/src/libwebm/PRESUBMIT.py
Normal file
202
lib/lib_audio/ESP8266Audio/src/libwebm/PRESUBMIT.py
Normal file
@ -0,0 +1,202 @@
|
||||
# Copyright (c) 2021, Google Inc. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
#
|
||||
# * Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in
|
||||
# the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
#
|
||||
# * Neither the name of Google nor the names of its contributors may
|
||||
# be used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
"""Top-level presubmit script for libwebm.
|
||||
|
||||
See https://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts for
|
||||
details on the presubmit API built into depot_tools.
|
||||
"""
|
||||
import re
|
||||
import subprocess2
|
||||
|
||||
USE_PYTHON3 = True
|
||||
_BASH_INDENTATION = "2"
|
||||
_GIT_COMMIT_SUBJECT_LENGTH = 65
|
||||
_INCLUDE_BASH_FILES_ONLY = [r".*\.sh$"]
|
||||
_INCLUDE_SOURCE_FILES_ONLY = [r".*\.(c|cc|[hc]pp|h)$"]
|
||||
_LIBWEBM_MAX_LINE_LENGTH = 80
|
||||
|
||||
|
||||
def _CheckCommitSubjectLength(input_api, output_api):
|
||||
"""Ensures commit's subject length is no longer than 65 chars."""
|
||||
name = "git-commit subject"
|
||||
cmd = ["git", "log", "-1", "--pretty=%s"]
|
||||
start = input_api.time.time()
|
||||
proc = subprocess2.Popen(
|
||||
cmd,
|
||||
stderr=subprocess2.PIPE,
|
||||
stdout=subprocess2.PIPE,
|
||||
universal_newlines=True)
|
||||
|
||||
stdout, _ = proc.communicate()
|
||||
duration = input_api.time.time() - start
|
||||
|
||||
if not re.match(r"^Revert",
|
||||
stdout) and (len(stdout) - 1) > _GIT_COMMIT_SUBJECT_LENGTH:
|
||||
failure_msg = (
|
||||
"The commit subject: %s is too long (%d chars)\n"
|
||||
"Try to keep this to 50 or less (up to 65 is permitted for "
|
||||
"non-reverts).\n"
|
||||
"https://www.git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-"
|
||||
"Project#_commit_guidelines") % (stdout, len(stdout) - 1)
|
||||
return output_api.PresubmitError("%s\n (%4.2fs) failed\n%s" %
|
||||
(name, duration, failure_msg))
|
||||
|
||||
return output_api.PresubmitResult("%s\n (%4.2fs) success" % (name, duration))
|
||||
|
||||
|
||||
def _GetFilesToSkip(input_api):
|
||||
"""Skips libwebm-specific files."""
|
||||
return list(input_api.DEFAULT_FILES_TO_SKIP) + [
|
||||
r"\.pylintrc$",
|
||||
]
|
||||
|
||||
|
||||
def _CheckChangeLintsClean(input_api, output_api):
|
||||
"""Makes sure that libwebm/ code is cpplint clean."""
|
||||
sources = lambda x: input_api.FilterSourceFile(
|
||||
x, files_to_check=_INCLUDE_SOURCE_FILES_ONLY, files_to_skip=None)
|
||||
return input_api.canned_checks.CheckChangeLintsClean(input_api, output_api,
|
||||
sources)
|
||||
|
||||
|
||||
def _RunShellCheckCmd(input_api, output_api, bash_file):
|
||||
"""shellcheck command wrapper."""
|
||||
cmd = ["shellcheck", "-x", "-oall", "-sbash", bash_file]
|
||||
name = "Check %s file." % bash_file
|
||||
start = input_api.time.time()
|
||||
output, rc = subprocess2.communicate(
|
||||
cmd, stdout=None, stderr=subprocess2.PIPE, universal_newlines=True)
|
||||
duration = input_api.time.time() - start
|
||||
if rc == 0:
|
||||
return output_api.PresubmitResult("%s\n%s (%4.2fs)\n" %
|
||||
(name, " ".join(cmd), duration))
|
||||
return output_api.PresubmitError("%s\n%s (%4.2fs) failed\n%s" %
|
||||
(name, " ".join(cmd), duration, output[1]))
|
||||
|
||||
|
||||
def _RunShfmtCheckCmd(input_api, output_api, bash_file):
|
||||
"""shfmt command wrapper."""
|
||||
cmd = [
|
||||
"shfmt", "-i", _BASH_INDENTATION, "-bn", "-ci", "-sr", "-kp", "-d",
|
||||
bash_file
|
||||
]
|
||||
name = "Check %s file." % bash_file
|
||||
start = input_api.time.time()
|
||||
output, rc = subprocess2.communicate(
|
||||
cmd, stdout=None, stderr=subprocess2.PIPE, universal_newlines=True)
|
||||
duration = input_api.time.time() - start
|
||||
if rc == 0:
|
||||
return output_api.PresubmitResult("%s\n%s (%4.2fs)\n" %
|
||||
(name, " ".join(cmd), duration))
|
||||
return output_api.PresubmitError("%s\n%s (%4.2fs) failed\n%s" %
|
||||
(name, " ".join(cmd), duration, output[1]))
|
||||
|
||||
|
||||
def _RunCmdOnCheckedFiles(input_api, output_api, run_cmd, files_to_check):
|
||||
"""Ensure that libwebm/ files are clean."""
|
||||
file_filter = lambda x: input_api.FilterSourceFile(
|
||||
x, files_to_check=files_to_check, files_to_skip=None)
|
||||
|
||||
affected_files = input_api.change.AffectedFiles(file_filter=file_filter)
|
||||
results = [
|
||||
run_cmd(input_api, output_api, f.AbsoluteLocalPath())
|
||||
for f in affected_files
|
||||
]
|
||||
return results
|
||||
|
||||
|
||||
def _CommonChecks(input_api, output_api):
|
||||
results = []
|
||||
results.extend(
|
||||
input_api.canned_checks.CheckChangeHasNoCrAndHasOnlyOneEol(
|
||||
input_api, output_api))
|
||||
results.extend(
|
||||
input_api.canned_checks.CheckChangeHasNoTabs(input_api, output_api))
|
||||
results.extend(
|
||||
input_api.canned_checks.CheckChangeHasNoStrayWhitespace(
|
||||
input_api, output_api))
|
||||
results.append(_CheckCommitSubjectLength(input_api, output_api))
|
||||
|
||||
source_file_filter = lambda x: input_api.FilterSourceFile(
|
||||
x, files_to_skip=_GetFilesToSkip(input_api))
|
||||
results.extend(
|
||||
input_api.canned_checks.CheckLongLines(
|
||||
input_api,
|
||||
output_api,
|
||||
maxlen=_LIBWEBM_MAX_LINE_LENGTH,
|
||||
source_file_filter=source_file_filter))
|
||||
|
||||
results.extend(
|
||||
input_api.canned_checks.CheckPatchFormatted(
|
||||
input_api,
|
||||
output_api,
|
||||
check_clang_format=True,
|
||||
check_python=True,
|
||||
result_factory=output_api.PresubmitError))
|
||||
results.extend(_CheckChangeLintsClean(input_api, output_api))
|
||||
|
||||
# Run pylint.
|
||||
results.extend(
|
||||
input_api.canned_checks.RunPylint(
|
||||
input_api,
|
||||
output_api,
|
||||
files_to_skip=_GetFilesToSkip(input_api),
|
||||
pylintrc=".pylintrc",
|
||||
version="2.7"))
|
||||
|
||||
# Binaries shellcheck and shfmt are not installed in depot_tools.
|
||||
# Installation is needed
|
||||
try:
|
||||
subprocess2.communicate(["shellcheck", "--version"])
|
||||
results.extend(
|
||||
_RunCmdOnCheckedFiles(input_api, output_api, _RunShellCheckCmd,
|
||||
_INCLUDE_BASH_FILES_ONLY))
|
||||
print("shfmt")
|
||||
subprocess2.communicate(["shfmt", "-version"])
|
||||
results.extend(
|
||||
_RunCmdOnCheckedFiles(input_api, output_api, _RunShfmtCheckCmd,
|
||||
_INCLUDE_BASH_FILES_ONLY))
|
||||
except OSError as os_error:
|
||||
results.append(
|
||||
output_api.PresubmitPromptWarning(
|
||||
"%s\nPlease install missing binaries locally." % os_error.args[0]))
|
||||
return results
|
||||
|
||||
|
||||
def CheckChangeOnUpload(input_api, output_api):
|
||||
results = []
|
||||
results.extend(_CommonChecks(input_api, output_api))
|
||||
return results
|
||||
|
||||
|
||||
def CheckChangeOnCommit(input_api, output_api):
|
||||
results = []
|
||||
results.extend(_CommonChecks(input_api, output_api))
|
||||
return results
|
148
lib/lib_audio/ESP8266Audio/src/libwebm/README.libwebm
Normal file
148
lib/lib_audio/ESP8266Audio/src/libwebm/README.libwebm
Normal file
@ -0,0 +1,148 @@
|
||||
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
|
||||
|
||||
Bug reports
|
||||
|
||||
Bug reports can be filed in the libwebm issue tracker:
|
||||
https://issues.webmproject.org/.
|
||||
For security reports, select 'Security report' from the Template dropdown.
|
@ -0,0 +1,4 @@
|
||||
# This file is used by git cl to get repository specific information.
|
||||
GERRIT_HOST: True
|
||||
CODE_REVIEW_SERVER: chromium-review.googlesource.com
|
||||
GERRIT_SQUASH_UPLOADS: False
|
193
lib/lib_audio/ESP8266Audio/src/libwebm/common/webmids.h
Normal file
193
lib/lib_audio/ESP8266Audio/src/libwebm/common/webmids.h
Normal file
@ -0,0 +1,193 @@
|
||||
// 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,
|
||||
kMkvColourSpace = 0x2EB524,
|
||||
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_
|
4204
lib/lib_audio/ESP8266Audio/src/libwebm/mkvmuxer/mkvmuxer.cc
Normal file
4204
lib/lib_audio/ESP8266Audio/src/libwebm/mkvmuxer/mkvmuxer.cc
Normal file
File diff suppressed because it is too large
Load Diff
1924
lib/lib_audio/ESP8266Audio/src/libwebm/mkvmuxer/mkvmuxer.h
Normal file
1924
lib/lib_audio/ESP8266Audio/src/libwebm/mkvmuxer/mkvmuxer.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -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_
|
737
lib/lib_audio/ESP8266Audio/src/libwebm/mkvmuxer/mkvmuxerutil.cc
Normal file
737
lib/lib_audio/ESP8266Audio/src/libwebm/mkvmuxer/mkvmuxerutil.cc
Normal file
@ -0,0 +1,737 @@
|
||||
// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the LICENSE file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
#include "mkvmuxerutil.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.h"
|
||||
#include "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<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_t* major, int32_t* minor, int32_t* build, int32_t* revision) {
|
||||
*major = 0;
|
||||
*minor = 3;
|
||||
*build = 3;
|
||||
*revision = 0;
|
||||
}
|
||||
|
||||
uint64 MakeUID(unsigned int* seed) {
|
||||
uint64 uid = 0;
|
||||
|
||||
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 _WIN32
|
||||
(void)seed;
|
||||
const int32 nn = rand();
|
||||
#elif defined(__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;
|
||||
#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
|
115
lib/lib_audio/ESP8266Audio/src/libwebm/mkvmuxer/mkvmuxerutil.h
Normal file
115
lib/lib_audio/ESP8266Audio/src/libwebm/mkvmuxer/mkvmuxerutil.h
Normal file
@ -0,0 +1,115 @@
|
||||
// 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 <stdint.h>
|
||||
|
||||
#include "mkvmuxertypes.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);
|
||||
|
||||
// Writes out |f| in Big Endian order. Returns 0 on success.
|
||||
int32 SerializeFloat(IMkvWriter* writer, float f);
|
||||
|
||||
// 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_t* major, int32_t* minor, int32_t* build, int32_t* 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_
|
99
lib/lib_audio/ESP8266Audio/src/libwebm/mkvmuxer/mkvwriter.cc
Normal file
99
lib/lib_audio/ESP8266Audio/src/libwebm/mkvmuxer/mkvwriter.cc
Normal file
@ -0,0 +1,99 @@
|
||||
// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style license
|
||||
// that can be found in the LICENSE file in the root of the source
|
||||
// tree. An additional intellectual property rights grant can be found
|
||||
// in the file PATENTS. All contributing project authors may
|
||||
// be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
#include "mkvwriter.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), use_write_cb_(false) {}
|
||||
|
||||
MkvWriter::MkvWriter(void* userdata, int(*cb)(void* userdata, const void* buffer, uint32 length)) : write_cb_(cb), cb_userdata_(userdata), writer_owns_file_(false), use_write_cb_(true) {}
|
||||
|
||||
MkvWriter::~MkvWriter() { Close(); }
|
||||
|
||||
int32 MkvWriter::Write(const void* buffer, uint32 length) {
|
||||
if (!file_ && !write_cb_)
|
||||
return -1;
|
||||
|
||||
if (length == 0)
|
||||
return 0;
|
||||
|
||||
if (buffer == NULL)
|
||||
return -1;
|
||||
|
||||
size_t bytes_written = 0;
|
||||
if(!use_write_cb_){
|
||||
bytes_written = file_->write((const uint8_t *)buffer, (size_t)length);
|
||||
} else {
|
||||
bytes_written = write_cb_(cb_userdata_, buffer, length);
|
||||
write_cb_written_ += bytes_written;
|
||||
}
|
||||
|
||||
return (bytes_written == length) ? 0 : -1;
|
||||
}
|
||||
|
||||
bool MkvWriter::Open(const char* filename) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void MkvWriter::Close() {
|
||||
if (file_ && writer_owns_file_) {
|
||||
file_->close();
|
||||
}
|
||||
file_ = NULL;
|
||||
}
|
||||
|
||||
int64 MkvWriter::Position() const {
|
||||
if (!file_ || use_write_cb_)
|
||||
return write_cb_written_;
|
||||
|
||||
return file_->position();
|
||||
}
|
||||
|
||||
int32 MkvWriter::Position(int64 position) {
|
||||
if (use_write_cb_ && write_cb_written_ == position)
|
||||
return 0;
|
||||
if (!file_ || use_write_cb_)
|
||||
return -1;
|
||||
|
||||
return file_->seek(position);
|
||||
|
||||
// #ifdef _MSC_VER
|
||||
// return _fseeki64(file_, position, SEEK_SET);
|
||||
// #elif defined(_WIN32)
|
||||
// return fseeko64(file_, static_cast<off_t>(position), SEEK_SET);
|
||||
// #elif !(defined(__ANDROID__) && __ANDROID_API__ < 24 && !defined(__LP64__) && \
|
||||
// defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64)
|
||||
// // POSIX.1 has fseeko and ftello. fseeko and ftello are not available before
|
||||
// // Android API level 24. See
|
||||
// // https://android.googlesource.com/platform/bionic/+/main/docs/32-bit-abi.md
|
||||
// // return fseeko(file_, static_cast<off_t>(position), SEEK_SET);
|
||||
// #else
|
||||
// return fseek(file_, static_cast<long>(position), SEEK_SET);
|
||||
// #endif
|
||||
// return -1;
|
||||
}
|
||||
|
||||
bool MkvWriter::Seekable() const {
|
||||
if (!file_ || use_write_cb_)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MkvWriter::ElementStartNotify(uint64, int64) {}
|
||||
|
||||
} // namespace mkvmuxer
|
58
lib/lib_audio/ESP8266Audio/src/libwebm/mkvmuxer/mkvwriter.h
Normal file
58
lib/lib_audio/ESP8266Audio/src/libwebm/mkvmuxer/mkvwriter.h
Normal file
@ -0,0 +1,58 @@
|
||||
// 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 "Fs.h"
|
||||
|
||||
#include "mkvmuxer.h"
|
||||
#include "mkvmuxertypes.h"
|
||||
|
||||
namespace mkvmuxer {
|
||||
|
||||
// Default implementation of the IMkvWriter interface on Windows.
|
||||
class MkvWriter : public IMkvWriter {
|
||||
public:
|
||||
MkvWriter();
|
||||
MkvWriter(File* fp);
|
||||
MkvWriter(void* userdata, int(*cb)(void* userdata, const void* buffer, uint32 length));
|
||||
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_;
|
||||
// Callback function to output stream.
|
||||
int(*write_cb_)(void* userdata, const void* buffer, uint32 length);
|
||||
void* cb_userdata_;
|
||||
bool writer_owns_file_;
|
||||
bool use_write_cb_;
|
||||
uint32_t write_cb_written_ = 0;
|
||||
|
||||
LIBWEBM_DISALLOW_COPY_AND_ASSIGN(MkvWriter);
|
||||
};
|
||||
|
||||
} // namespace mkvmuxer
|
||||
|
||||
#endif // MKVMUXER_MKVWRITER_H_
|
8107
lib/lib_audio/ESP8266Audio/src/libwebm/mkvparser/mkvparser.cc
Normal file
8107
lib/lib_audio/ESP8266Audio/src/libwebm/mkvparser/mkvparser.cc
Normal file
File diff suppressed because it is too large
Load Diff
1147
lib/lib_audio/ESP8266Audio/src/libwebm/mkvparser/mkvparser.h
Normal file
1147
lib/lib_audio/ESP8266Audio/src/libwebm/mkvparser/mkvparser.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -59,6 +59,12 @@ enum : uint32_t {
|
||||
OPUS_DECODER = 2,
|
||||
};
|
||||
|
||||
// I2S encoder type
|
||||
enum : uint8_t {
|
||||
MP3_ENCODER = 1,
|
||||
OPUS_ENCODER = 2,
|
||||
};
|
||||
|
||||
#define I2S_SLOTS 2
|
||||
#define AUDIO_SETTINGS_VERSION 2
|
||||
|
||||
|
@ -93,19 +93,20 @@ struct AUDIO_I2S_MP3_t {
|
||||
#endif // defined(USE_I2S_MP3) || defined(USE_I2S_WEBRADIO)
|
||||
|
||||
char mic_path[32];
|
||||
uint8_t mic_stop;
|
||||
int8_t mic_error;
|
||||
bool mic_stop = false;
|
||||
bool use_stream = false;
|
||||
bool task_running = false;
|
||||
bool task_has_ended = false;
|
||||
bool task_loop_mode = false;
|
||||
|
||||
// SHINE
|
||||
// RECORD/STREAM/ENCODING
|
||||
uint32_t recdur;
|
||||
uint8_t stream_active;
|
||||
uint8_t stream_enable;
|
||||
uint8_t encoder_type;
|
||||
bool stream_active;
|
||||
bool stream_enable;
|
||||
WiFiClient client;
|
||||
ESP8266WebServer *MP3Server;
|
||||
ESP8266WebServer *StreamServer;
|
||||
|
||||
// I2S_BRIDGE
|
||||
BRIDGE_MODE bridge_mode;
|
||||
@ -344,182 +345,6 @@ void CmndI2SConfig(void) {
|
||||
cfg->rx.dma_desc_num
|
||||
);
|
||||
}
|
||||
/*********************************************************************************************\
|
||||
* microphone related functions
|
||||
\*********************************************************************************************/
|
||||
|
||||
// micro to mp3 file or stream
|
||||
void I2sMicTask(void *arg){
|
||||
int8_t error = 0;
|
||||
uint8_t *ucp;
|
||||
int written;
|
||||
shine_config_t config;
|
||||
shine_t s = nullptr;
|
||||
uint16_t samples_per_pass;
|
||||
File mp3_out = (File)nullptr;
|
||||
int16_t *buffer = nullptr;
|
||||
uint16_t bytesize;
|
||||
uint16_t bwritten;
|
||||
uint32_t ctime;
|
||||
uint32_t gain = audio_i2s.Settings->rx.gain;
|
||||
uint32_t timeForOneRead;
|
||||
|
||||
if (!audio_i2s_mp3.use_stream) {
|
||||
mp3_out = ufsp->open(audio_i2s_mp3.mic_path, "w");
|
||||
if (!mp3_out) {
|
||||
error = 1;
|
||||
goto exit;
|
||||
}
|
||||
} else {
|
||||
if (!audio_i2s_mp3.stream_active) {
|
||||
error = 2;
|
||||
audio_i2s_mp3.use_stream = 0;
|
||||
goto exit;
|
||||
}
|
||||
audio_i2s_mp3.client.flush();
|
||||
audio_i2s_mp3.client.setTimeout(3);
|
||||
audio_i2s_mp3.client.print("HTTP/1.1 200 OK\r\n"
|
||||
"Content-Type: audio/mpeg;\r\n\r\n");
|
||||
|
||||
// Webserver->send(200, "application/octet-stream", "");
|
||||
//"Content-Type: audio/mp3;\r\n\r\n");
|
||||
}
|
||||
|
||||
shine_set_config_mpeg_defaults(&config.mpeg);
|
||||
|
||||
if (audio_i2s.Settings->rx.channels == 1) {
|
||||
config.mpeg.mode = MONO;
|
||||
} else {
|
||||
config.mpeg.mode = STEREO;
|
||||
}
|
||||
// config.mpeg.bitr = 128; - this is default anyway, but maybe we want to make it a variable in the future
|
||||
config.wave.samplerate = audio_i2s.Settings->rx.sample_rate;
|
||||
config.wave.channels = (channels)(audio_i2s.Settings->rx.channels);
|
||||
|
||||
if (shine_check_config(config.wave.samplerate, config.mpeg.bitr) < 0) {
|
||||
error = 3;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
s = shine_initialise(&config);
|
||||
if (!s) {
|
||||
error = 4;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
samples_per_pass = shine_samples_per_pass(s);
|
||||
bytesize = samples_per_pass * 2 * (audio_i2s.Settings->rx.channels);
|
||||
|
||||
buffer = (int16_t*)malloc(bytesize);
|
||||
if (!buffer) {
|
||||
error = 5;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ctime = TasmotaGlobal.uptime;
|
||||
timeForOneRead = 1000 / ((audio_i2s.Settings->rx.sample_rate / (samples_per_pass * audio_i2s.Settings->rx.channels )));
|
||||
timeForOneRead -= 1; // be very in time
|
||||
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("I2S: samples %u, bytesize %u, time: %u"),samples_per_pass, bytesize, timeForOneRead);
|
||||
|
||||
while (!audio_i2s_mp3.mic_stop) {
|
||||
TickType_t xLastWakeTime = xTaskGetTickCount();
|
||||
size_t bytes_read;
|
||||
|
||||
// bytes_read = audio_i2s.in->readMic((uint8_t*)buffer, bytesize, true /*dc_block*/, false /*apply_gain*/, true /*lowpass*/, nullptr /*peak_ptr*/);
|
||||
i2s_channel_read(audio_i2s.in->getRxHandle(), (void*)buffer, bytesize, &bytes_read, pdMS_TO_TICKS(3));
|
||||
|
||||
if(bytes_read < bytesize) AddLog(LOG_LEVEL_DEBUG, PSTR("!! %u, %u"), bytes_read, bytesize);
|
||||
|
||||
if (gain > 1) {
|
||||
// set gain the "old way"
|
||||
int16_t _gain = gain / 16;
|
||||
for (uint32_t cnt = 0; cnt < bytes_read / 2; cnt++) {
|
||||
buffer[cnt] *= _gain;
|
||||
}
|
||||
}
|
||||
ucp = shine_encode_buffer_interleaved(s, buffer, &written);
|
||||
|
||||
if (!audio_i2s_mp3.use_stream) {
|
||||
bwritten = mp3_out.write(ucp, written);
|
||||
if (bwritten != written) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
audio_i2s_mp3.client.write((const char*)ucp, written);
|
||||
|
||||
if (!audio_i2s_mp3.client.connected()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
audio_i2s_mp3.recdur = TasmotaGlobal.uptime - ctime;
|
||||
|
||||
vTaskDelayUntil( &xLastWakeTime, pdMS_TO_TICKS(timeForOneRead));
|
||||
}
|
||||
|
||||
ucp = shine_flush(s, &written);
|
||||
|
||||
if (!audio_i2s_mp3.use_stream) {
|
||||
mp3_out.write(ucp, written);
|
||||
} else {
|
||||
audio_i2s_mp3.client.write((const char*)ucp, written);
|
||||
}
|
||||
|
||||
|
||||
exit:
|
||||
if (s) {
|
||||
shine_close(s);
|
||||
}
|
||||
if (mp3_out) {
|
||||
mp3_out.close();
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("I2S: MP3 file closed"));
|
||||
}
|
||||
if (buffer) {
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
if (audio_i2s_mp3.use_stream) {
|
||||
audio_i2s_mp3.client.stop();
|
||||
}
|
||||
|
||||
audio_i2s.in->stopRx();
|
||||
audio_i2s_mp3.mic_stop = 0;
|
||||
audio_i2s_mp3.mic_error = error;
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("I2S: mp3task result code: %d"), error);
|
||||
audio_i2s_mp3.mic_task_handle = 0;
|
||||
audio_i2s_mp3.recdur = 0;
|
||||
audio_i2s_mp3.stream_active = 0;
|
||||
vTaskDelete(NULL);
|
||||
|
||||
}
|
||||
|
||||
int32_t I2sRecordShine(char *path) {
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
switch(audio_i2s.Settings->rx.sample_rate){
|
||||
case 32000: case 48000: case 44100:
|
||||
break; // supported
|
||||
default:
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("I2S: unsupported sample rate for MP3 encoding: %d"), audio_i2s.Settings->rx.sample_rate);
|
||||
return -1;
|
||||
}
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("I2S: accepted sample rate for MP3 encoding: %d"), audio_i2s.Settings->rx.sample_rate);
|
||||
|
||||
#ifdef USE_I2S_MP3
|
||||
if (audio_i2s_mp3.decoder) return 0;
|
||||
#endif
|
||||
|
||||
strlcpy(audio_i2s_mp3.mic_path, path, sizeof(audio_i2s_mp3.mic_path));
|
||||
audio_i2s_mp3.mic_stop = 0;
|
||||
uint32_t stack = 8000;
|
||||
audio_i2s_mp3.use_stream = !strcmp(audio_i2s_mp3.mic_path, "stream.mp3");
|
||||
|
||||
audio_i2s.in->startRx();
|
||||
|
||||
err = xTaskCreatePinnedToCore(I2sMicTask, "MIC", stack, NULL, 3, &audio_i2s_mp3.mic_task_handle, 1);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Driver Settings load and save using filesystem
|
||||
@ -1114,42 +939,31 @@ void CmndI2SMicRec(void) {
|
||||
ResponseCmndChar("I2S Mic not configured");
|
||||
return;
|
||||
}
|
||||
if (audio_i2s_mp3.preallocateCodec == nullptr){
|
||||
AddLog(LOG_LEVEL_DEBUG,PSTR("I2S: try late codec buffer allocation"));
|
||||
audio_i2s_mp3.preallocateCodec = special_malloc(preallocateCodecSize);
|
||||
}
|
||||
if (audio_i2s_mp3.preallocateCodec != nullptr) {
|
||||
if (XdrvMailbox.data_len > 0) {
|
||||
if (!strncmp(XdrvMailbox.data, "-?", 2)) {
|
||||
Response_P("{\"I2SREC-duration\":%d}", audio_i2s_mp3.recdur);
|
||||
} else {
|
||||
int err = I2sRecordShine(XdrvMailbox.data);
|
||||
if(err == pdPASS){
|
||||
ResponseCmndChar(XdrvMailbox.data);
|
||||
} else {
|
||||
ResponseCmndChar_P(PSTR("Did not launch recording task"));
|
||||
}
|
||||
}
|
||||
|
||||
if (XdrvMailbox.data_len > 0) {
|
||||
if (!strncmp(XdrvMailbox.data, "-?", 2)) {
|
||||
Response_P("{\"I2SREC-duration\":%d}", audio_i2s_mp3.recdur);
|
||||
} else {
|
||||
if (audio_i2s_mp3.mic_task_handle) {
|
||||
// stop task
|
||||
audio_i2s_mp3.mic_stop = 1;
|
||||
while (audio_i2s_mp3.mic_stop) {
|
||||
delay(1);
|
||||
}
|
||||
ResponseCmndChar_P(PSTR("Stopped"));
|
||||
}
|
||||
else {
|
||||
ResponseCmndChar_P(PSTR("No running recording"));
|
||||
audio_i2s_mp3.use_stream = false;
|
||||
int err = I2sRecord(XdrvMailbox.data, XdrvMailbox.index);
|
||||
// int err = I2sRecordShine(XdrvMailbox.data);
|
||||
if(err == pdPASS){
|
||||
ResponseCmndChar(XdrvMailbox.data);
|
||||
} else {
|
||||
ResponseCmndChar_P(PSTR("Did not launch recording task"));
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
if (audio_i2s.in){
|
||||
ResponseCmndChar_P(PSTR("need PSRAM for MP3 recording"));
|
||||
} else {
|
||||
if (audio_i2s_mp3.mic_task_handle) {
|
||||
// stop task
|
||||
audio_i2s_mp3.mic_stop = 1;
|
||||
while (audio_i2s_mp3.mic_stop) {
|
||||
delay(1);
|
||||
}
|
||||
ResponseCmndChar_P(PSTR("Stopped"));
|
||||
}
|
||||
else{
|
||||
ResponseCmndChar_P(PSTR("no mic configured"));
|
||||
else {
|
||||
ResponseCmndChar_P(PSTR("No running recording"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1158,7 +972,7 @@ void CmndI2SMicRec(void) {
|
||||
* Interface
|
||||
\*********************************************************************************************/
|
||||
|
||||
void I2sMp3Loop(void);
|
||||
void I2sStreamLoop(void);
|
||||
void I2sMp3Init(uint32_t on);
|
||||
void MP3ShowStream(void);
|
||||
|
||||
@ -1177,17 +991,12 @@ bool Xdrv42(uint32_t function) {
|
||||
break;
|
||||
case FUNC_LOOP:
|
||||
#if defined(USE_SHINE) && defined(MP3_MIC_STREAM)
|
||||
I2sMp3Loop();
|
||||
I2sStreamLoop();
|
||||
#endif
|
||||
#if defined(I2S_BRIDGE)
|
||||
i2s_bridge_loop();
|
||||
#endif
|
||||
break;
|
||||
case FUNC_WEB_ADD_HANDLER:
|
||||
#if defined(USE_SHINE) && defined(MP3_MIC_STREAM)
|
||||
// audio_i2s.Settings->tx.stream_enable = 1;
|
||||
// I2sMp3Init(1);
|
||||
#endif
|
||||
#if defined(I2S_BRIDGE)
|
||||
I2SBridgeInit();
|
||||
#endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
xdrv_42_i2s_audio.ino - Audio dac support for Tasmota
|
||||
xdrv_42_i2s_mp3mic.ino - Audio dac support for Tasmota
|
||||
|
||||
Copyright (C) 2021 Gerhard Mutz and Theo Arends
|
||||
|
||||
@ -21,219 +21,397 @@
|
||||
#if defined(ESP32) && ESP_IDF_VERSION_MAJOR >= 5
|
||||
#ifdef USE_I2S_AUDIO
|
||||
|
||||
// uint32_t SpeakerMic(uint8_t spkr) {
|
||||
// esp_err_t err = ESP_OK;
|
||||
class AudioEncoder
|
||||
{
|
||||
public:
|
||||
AudioEncoder() {
|
||||
inBuffer = nullptr;
|
||||
outFrame = nullptr;
|
||||
samplesPerPass = 0;
|
||||
byteSize = 0;
|
||||
};
|
||||
virtual ~AudioEncoder() {};
|
||||
virtual uint32_t begin(uint32_t samplingRate, uint32_t inputChannels) { return 0; };
|
||||
virtual int encode(size_t samples) { return 0; };
|
||||
virtual size_t stop() { return 0; };
|
||||
virtual void setCB(void *cb){};
|
||||
|
||||
// // audio_i2s.mode = spkr;
|
||||
// return err;
|
||||
// }
|
||||
public:
|
||||
int16_t *inBuffer;
|
||||
uint8_t *outFrame;
|
||||
uint32_t samplesPerPass;
|
||||
uint32_t byteSize;
|
||||
File *file;
|
||||
WiFiClient *client;
|
||||
};
|
||||
|
||||
// #ifdef USE_SHINE
|
||||
#ifdef MP3_MIC_STREAM
|
||||
class AudioEncoderShineMP3 : public AudioEncoder
|
||||
{
|
||||
public:
|
||||
AudioEncoderShineMP3(File *rec_file, WiFiClient *wifi) {
|
||||
file = rec_file;
|
||||
client = wifi;
|
||||
};
|
||||
virtual ~AudioEncoderShineMP3() {
|
||||
if (s) {shine_close(s);}
|
||||
if(inBuffer){free(inBuffer); }
|
||||
if(file) {file->close();}
|
||||
if(client) {client->stop();}
|
||||
};
|
||||
virtual uint32_t begin(uint32_t samplingRate, uint32_t inputChannels) {
|
||||
shine_set_config_mpeg_defaults(&config.mpeg);
|
||||
if (inputChannels == 1) {
|
||||
config.mpeg.mode = MONO;
|
||||
} else {
|
||||
config.mpeg.mode = STEREO;
|
||||
}
|
||||
config.wave.samplerate = samplingRate;
|
||||
config.wave.channels = (channels)inputChannels;
|
||||
if (shine_check_config(config.wave.samplerate, config.mpeg.bitr) < 0) {return 3;}
|
||||
s = shine_initialise(&config);
|
||||
if (!s) {return 4; }
|
||||
|
||||
// #include <layer3.h>
|
||||
// #include <types.h>
|
||||
samplesPerPass = shine_samples_per_pass(s);
|
||||
byteSize = samplesPerPass * 2 * inputChannels;
|
||||
|
||||
// // micro to mp3 file or stream
|
||||
// void mic_task(void *arg){
|
||||
// int8_t error = 0;
|
||||
// uint8_t *ucp;
|
||||
// int written;
|
||||
// shine_config_t config;
|
||||
// shine_t s = nullptr;
|
||||
// uint16_t samples_per_pass;
|
||||
// File mp3_out = (File)nullptr;
|
||||
// int16_t *buffer = nullptr;
|
||||
// uint16_t bytesize;
|
||||
// uint16_t bwritten;
|
||||
// uint32_t ctime;
|
||||
inBuffer = (int16_t*)malloc(byteSize); // byteSize = samplesPerPass * sizeof(int16_t)
|
||||
if (!inBuffer) {return 5; }
|
||||
return 0;
|
||||
};
|
||||
|
||||
// if (!audio_i2s_mp3.use_stream) {
|
||||
// mp3_out = ufsp->open(audio_i2s_mp3.mic_path, "w");
|
||||
// if (!mp3_out) {
|
||||
// error = 1;
|
||||
// goto exit;
|
||||
// }
|
||||
// } else {
|
||||
// if (!audio_i2s_mp3.stream_active) {
|
||||
// error = 2;
|
||||
// audio_i2s_mp3.use_stream = 0;
|
||||
// goto exit;
|
||||
// }
|
||||
// audio_i2s_mp3.client.flush();
|
||||
// audio_i2s_mp3.client.setTimeout(3);
|
||||
// audio_i2s_mp3.client.print("HTTP/1.1 200 OK\r\n"
|
||||
// "Content-Type: audio/mpeg;\r\n\r\n");
|
||||
virtual size_t stop() {
|
||||
int written;
|
||||
outFrame = shine_flush(s, &written);
|
||||
return written;
|
||||
}
|
||||
|
||||
// // Webserver->send(200, "application/octet-stream", "");
|
||||
// //"Content-Type: audio/mp3;\r\n\r\n");
|
||||
// }
|
||||
virtual int encode(size_t samples) {
|
||||
int written;
|
||||
outFrame = shine_encode_buffer_interleaved(s, inBuffer, &written);
|
||||
return write(written);
|
||||
};
|
||||
|
||||
// shine_set_config_mpeg_defaults(&config.mpeg);
|
||||
protected:
|
||||
int write(int len){
|
||||
size_t written = 0;
|
||||
if(file != nullptr){
|
||||
written = file->write(outFrame,len);
|
||||
} else if (client != nullptr){
|
||||
if (client->connected()) {
|
||||
written = client->write(outFrame, len);
|
||||
}
|
||||
}
|
||||
return (written != (size_t)len);
|
||||
}
|
||||
shine_config_t config;
|
||||
shine_t s;
|
||||
};
|
||||
#endif //MP3_MIC_STREAM
|
||||
|
||||
// if (audio_i2s.Settings->rx.channels == 1) {
|
||||
// config.mpeg.mode = MONO;
|
||||
// } else {
|
||||
// config.mpeg.mode = STEREO;
|
||||
// }
|
||||
// config.mpeg.bitr = 128;
|
||||
// config.wave.samplerate = audio_i2s.Settings->rx.sample_rate;
|
||||
// config.wave.channels = (channels)audio_i2s.Settings->rx.channels;
|
||||
#ifdef USE_I2S_OPUS
|
||||
|
||||
// if (shine_check_config(config.wave.samplerate, config.mpeg.bitr) < 0) {
|
||||
// error = 3;
|
||||
// goto exit;
|
||||
// }
|
||||
#include "libwebm/mkvmuxer/mkvwriter.h"
|
||||
class AudioEncoderOpusWebm;
|
||||
typedef int (AudioEncoderOpusWebm::*packet_cb)(void *userdata, const void *buffer, size_t length);
|
||||
class AudioEncoderOpusWebm : public AudioEncoder
|
||||
{
|
||||
public:
|
||||
AudioEncoderOpusWebm(File *rec_file, WiFiClient *wifi) {
|
||||
file = rec_file;
|
||||
client = wifi;
|
||||
};
|
||||
|
||||
// s = shine_initialise(&config);
|
||||
// if (!s) {
|
||||
// error = 4;
|
||||
// goto exit;
|
||||
// }
|
||||
virtual ~AudioEncoderOpusWebm() {
|
||||
if(inBuffer){ free(inBuffer); }
|
||||
if(outFrame){ free(outFrame); }
|
||||
opus_encoder_destroy(encoder);
|
||||
if(file) {file->close();}
|
||||
if(client) {client->stop();}
|
||||
if(wifiBuffer){ free(wifiBuffer); }
|
||||
delete muxer;
|
||||
};
|
||||
|
||||
// samples_per_pass = shine_samples_per_pass(s);
|
||||
// bytesize = samples_per_pass * 2 * audio_i2s.Settings->rx.channels;
|
||||
virtual uint32_t begin(uint32_t samplingRate, uint32_t inputChannels) {
|
||||
int error;
|
||||
encoder = opus_encoder_create(samplingRate, inputChannels, samplingRate > 16000 ? OPUS_APPLICATION_AUDIO : OPUS_APPLICATION_VOIP, &error);
|
||||
if (error != 0) { return error; }
|
||||
opus_encoder_ctl(encoder, OPUS_SET_COMPLEXITY(complexity));
|
||||
int _preskip;
|
||||
opus_encoder_ctl(encoder, OPUS_GET_LOOKAHEAD((opus_int32*)&_preskip));
|
||||
opusHeader.samplingRate = samplingRate;
|
||||
opusHeader.inputChannels = inputChannels;
|
||||
opusHeader.preSkip = _preskip;
|
||||
|
||||
// buffer = (int16_t*)malloc(bytesize);
|
||||
// if (!buffer) {
|
||||
// error = 5;
|
||||
// goto exit;
|
||||
// }
|
||||
constexpr uint32_t frameDuration = 20; //ms
|
||||
samplesPerPass = samplingRate/(1000/frameDuration);
|
||||
byteSize = samplesPerPass * 2 * inputChannels;
|
||||
inBuffer = (int16_t*)malloc(byteSize);
|
||||
if (!inBuffer) {return 5; }
|
||||
outFrame = (uint8_t*)malloc(maxBytes);
|
||||
if (!outFrame) {return 5; }
|
||||
if(client){
|
||||
wifiBuffer = (uint8_t*)malloc(wifiBufferSize);
|
||||
if (!wifiBuffer) {return 5; }
|
||||
}
|
||||
|
||||
// ctime = TasmotaGlobal.uptime;
|
||||
if(file){
|
||||
muxer = new mkvmuxer::MkvWriter(file);
|
||||
} else if (client){
|
||||
muxer = new mkvmuxer::MkvWriter(this, &AudioEncoderOpusWebm::packet_cb);
|
||||
}
|
||||
timeCode = 0;
|
||||
if (!muxer) {return 6; }
|
||||
if (!muxerSegment.Init(muxer)) {return 7; }
|
||||
mkvmuxer::SegmentInfo* info = muxerSegment.GetSegmentInfo();
|
||||
if (info == nullptr) {return 8;}
|
||||
info->set_writing_app("Tasmota");
|
||||
// Add an audio track.
|
||||
trackNumber = muxerSegment.AddAudioTrack(samplingRate, inputChannels, 0);
|
||||
if (trackNumber == 0) {return 9; }
|
||||
mkvmuxer::AudioTrack* audio = static_cast<mkvmuxer::AudioTrack*>(muxerSegment.GetTrackByNumber(trackNumber));
|
||||
if (audio == nullptr) {return 10;}
|
||||
audio->set_codec_id(mkvmuxer::Tracks::kOpusCodecId);
|
||||
audio->set_bit_depth(16);
|
||||
audio->set_codec_delay(_preskip * 1000000 / samplingRate); // Delay built into the code during decoding in nanoseconds.
|
||||
audio->set_seek_pre_roll(80000000); // Amount of audio to discard after a seek - https://wiki.xiph.org/MatroskaOpus
|
||||
if (!audio->SetCodecPrivate( (const uint8_t*)&opusHeader, sizeof(opusHeader))) {return 11;}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// while (!audio_i2s_mp3.mic_stop) {
|
||||
// uint32_t bytes_read;
|
||||
// bytes_read = audio_i2s.in->readMic((uint8_t*)buffer, bytesize, true /*dc_block*/, false /*apply_gain*/, true /*lowpass*/, nullptr /*peak_ptr*/);
|
||||
// // i2s_read(audio_i2s.mic_port, (char *)buffer, bytesize, &bytes_read, (100 / portTICK_PERIOD_MS));
|
||||
virtual int encode(size_t samples) {
|
||||
opus_int32 len = opus_encode(encoder, inBuffer, samplesPerPass, outFrame, maxBytes);
|
||||
if (len < 0) { return -1; }
|
||||
if (len > 2) // ignore packets shorter than or equal to 2 bytes.
|
||||
{
|
||||
if(!muxerSegment.AddFrame(outFrame, len, trackNumber, timeCode, true)){
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
timeCode += 20000 * 1000; // 20 ms in nanoseconds
|
||||
return 0;
|
||||
}
|
||||
|
||||
// if (audio_i2s.Settings->rx.gain > 1) {
|
||||
// // set gain
|
||||
// for (uint32_t cnt = 0; cnt < bytes_read / 2; cnt++) {
|
||||
// buffer[cnt] *= audio_i2s.Settings->rx.gain;
|
||||
// }
|
||||
// }
|
||||
// ucp = shine_encode_buffer_interleaved(s, buffer, &written);
|
||||
virtual size_t stop() {
|
||||
bool success = muxerSegment.Finalize();
|
||||
muxer->Close();
|
||||
return success;
|
||||
}
|
||||
|
||||
// if (!audio_i2s.Settings->tx.stream_enable) {
|
||||
// bwritten = mp3_out.write(ucp, written);
|
||||
// if (bwritten != written) {
|
||||
// break;
|
||||
// }
|
||||
// } else {
|
||||
// audio_i2s_mp3.client.write((const char*)ucp, written);
|
||||
protected:
|
||||
OpusEncoder *encoder;
|
||||
const uint32_t maxBytes = 1296;
|
||||
const uint32_t complexity = 1; // 1-10 - low to high quality
|
||||
mkvmuxer::MkvWriter *muxer;
|
||||
mkvmuxer::Segment muxerSegment;
|
||||
|
||||
// if (!audio_i2s_mp3.client.connected()) {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// audio_i2s_mp3.recdur = TasmotaGlobal.uptime - ctime;
|
||||
// }
|
||||
uint64_t trackNumber = 0;
|
||||
uint64_t timeCode = 0;
|
||||
|
||||
// ucp = shine_flush(s, &written);
|
||||
struct __attribute__((packed)) {
|
||||
char signatureHead[8] = {'O', 'p', 'u', 's', 'H', 'e', 'a', 'd'};
|
||||
uint8_t version = 1;
|
||||
uint8_t inputChannels = 1;
|
||||
uint16_t preSkip = 3840;
|
||||
uint32_t samplingRate = 0;
|
||||
int16_t outputGain = 0;
|
||||
uint8_t channelMappingFamily = 0;
|
||||
} opusHeader;
|
||||
|
||||
// if (!audio_i2s_mp3.use_stream) {
|
||||
// mp3_out.write(ucp, written);
|
||||
// } else {
|
||||
// audio_i2s_mp3.client.write((const char*)ucp, written);
|
||||
// }
|
||||
static constexpr size_t wifiBufferSize = CONFIG_LWIP_TCP_MSS; // should be <= TCP Maximum Segment Size
|
||||
uint8_t *wifiBuffer;
|
||||
size_t wifiPtr = 0;
|
||||
|
||||
static int packet_cb(void *userdata, const void *buffer, size_t length){
|
||||
AudioEncoderOpusWebm *_enc = (AudioEncoderOpusWebm *)userdata;
|
||||
int result = length;
|
||||
if(_enc->wifiPtr + length > wifiBufferSize){
|
||||
size_t written;
|
||||
if (_enc->client->connected()) {
|
||||
written = _enc->client->write(_enc->wifiBuffer, _enc->wifiPtr);
|
||||
}
|
||||
result = written == _enc->wifiPtr ? length : -1; //TODO - maybe tolerate some send errors
|
||||
// AddLog(LOG_LEVEL_DEBUG, PSTR(">> %u, %u, %u"),written, _enc->wifiPtr, result);
|
||||
_enc->wifiPtr = 0;
|
||||
}
|
||||
memcpy(_enc->wifiBuffer + _enc->wifiPtr,(uint8_t*)buffer,length);
|
||||
_enc->wifiPtr += length;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
#endif // USE_I2S_OPUS
|
||||
|
||||
// exit:
|
||||
// if (s) {
|
||||
// shine_close(s);
|
||||
// }
|
||||
// if (mp3_out) {
|
||||
// mp3_out.close();
|
||||
// }
|
||||
// if (buffer) {
|
||||
// free(buffer);
|
||||
// }
|
||||
// micro to mp3/webm - file or stream
|
||||
void I2sMicTask(void *arg){
|
||||
int8_t error = 0;
|
||||
int written;
|
||||
|
||||
// if (audio_i2s_mp3.use_stream) {
|
||||
// audio_i2s_mp3.client.stop();
|
||||
// }
|
||||
AudioEncoder *mic_enc;
|
||||
File rec_file;
|
||||
File *rec_file_ptr = nullptr;
|
||||
|
||||
// SpeakerMic(I2S_AUDIO_MODE_SPK);
|
||||
// audio_i2s_mp3.mic_stop = 0;
|
||||
// audio_i2s_mp3.mic_error = error;
|
||||
// AddLog(LOG_LEVEL_INFO, PSTR("mp3task result code: %d"), error);
|
||||
// audio_i2s_mp3.mic_task_handle = 0;
|
||||
// audio_i2s_mp3.recdur = 0;
|
||||
// audio_i2s_mp3.stream_active = 0;
|
||||
// vTaskDelete(NULL);
|
||||
uint16_t bwritten;
|
||||
uint32_t ctime;
|
||||
uint32_t gain = audio_i2s.Settings->rx.gain;
|
||||
uint32_t timeForOneRead;
|
||||
uint32_t __enctime;
|
||||
TickType_t xLastWakeTime;
|
||||
|
||||
// }
|
||||
if (!audio_i2s_mp3.use_stream) {
|
||||
rec_file = ufsp->open(audio_i2s_mp3.mic_path, "w");
|
||||
if (!rec_file) {
|
||||
error = 1;
|
||||
goto exit;
|
||||
} else {
|
||||
rec_file_ptr = &rec_file;
|
||||
}
|
||||
} else {
|
||||
if (!audio_i2s_mp3.stream_active) {
|
||||
error = 2;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
// int32_t i2s_record_shine(char *path) {
|
||||
// esp_err_t err = ESP_OK;
|
||||
if(audio_i2s_mp3.encoder_type == MP3_ENCODER){
|
||||
#ifdef MP3_MIC_STREAM
|
||||
mic_enc = new AudioEncoderShineMP3(rec_file_ptr, &audio_i2s_mp3.client);
|
||||
#endif // MP3_MIC_STREAM
|
||||
} else {
|
||||
#ifdef USE_I2S_OPUS
|
||||
mic_enc = new AudioEncoderOpusWebm(rec_file_ptr, &audio_i2s_mp3.client);
|
||||
#endif // USE_I2S_OPUS
|
||||
}
|
||||
|
||||
// if (audio_i2s.in) {
|
||||
// if (audio_i2s_mp3.decoder || audio_i2s_mp3.mp3) return 0;
|
||||
// }
|
||||
if (audio_i2s_mp3.use_stream) {
|
||||
audio_i2s_mp3.client.flush();
|
||||
audio_i2s_mp3.client.setTimeout(3);
|
||||
if(audio_i2s_mp3.encoder_type == MP3_ENCODER){
|
||||
audio_i2s_mp3.client.print("HTTP/1.1 200 OK\r\n"
|
||||
"Content-Type: audio/mpeg;\r\n\r\n");
|
||||
} else if (audio_i2s_mp3.encoder_type == OPUS_ENCODER){
|
||||
audio_i2s_mp3.client.print("HTTP/1.1 200 OK\r\n"
|
||||
"Content-Type: audio/webm; codecs=opus\r\n\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
// err = SpeakerMic(I2S_AUDIO_MODE_MIC);
|
||||
// if (err) {
|
||||
// if (audio_i2s.in) {
|
||||
// SpeakerMic(I2S_AUDIO_MODE_SPK);
|
||||
// }
|
||||
// AddLog(LOG_LEVEL_INFO, PSTR("mic init error: %d"), err);
|
||||
// return err;
|
||||
// }
|
||||
error = mic_enc->begin(audio_i2s.Settings->rx.sample_rate, audio_i2s.Settings->rx.channels);
|
||||
if(error != 0){
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// strlcpy(audio_i2s_mp3.mic_path, path, sizeof(audio_i2s_mp3.mic_path));
|
||||
ctime = TasmotaGlobal.uptime;
|
||||
timeForOneRead = 1000 / ((audio_i2s.Settings->rx.sample_rate / (mic_enc->samplesPerPass * audio_i2s.Settings->rx.channels )));
|
||||
// timeForOneRead -= 1; // be very in time
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("I2S: samples %u, bytesize %u, time: %u"),mic_enc->samplesPerPass, mic_enc->byteSize, timeForOneRead);
|
||||
xLastWakeTime = xTaskGetTickCount();
|
||||
|
||||
// audio_i2s_mp3.mic_stop = 0;
|
||||
while (!audio_i2s_mp3.mic_stop) {
|
||||
size_t bytes_read;
|
||||
// bytes_read = audio_i2s.in->readMic((uint8_t*)mic_enc->inBuffer, mic_enc->byteSize, true /*dc_block*/, false /*apply_gain*/, true /*lowpass*/, nullptr /*peak_ptr*/);
|
||||
i2s_channel_read(audio_i2s.in->getRxHandle(), (void*)mic_enc->inBuffer, mic_enc->byteSize, &bytes_read, pdMS_TO_TICKS(1));
|
||||
|
||||
// uint32_t stack = 4096;
|
||||
if (gain > 1) {
|
||||
// set gain the "old way"
|
||||
int16_t _gain = gain / 16;
|
||||
for (uint32_t cnt = 0; cnt < bytes_read / 2; cnt++) {
|
||||
mic_enc->inBuffer[cnt] *= _gain;
|
||||
}
|
||||
}
|
||||
|
||||
// audio_i2s_mp3.use_stream = !strcmp(audio_i2s_mp3.mic_path, "stream.mp3");
|
||||
__enctime = millis();
|
||||
if(bytes_read != 0){
|
||||
written = mic_enc->encode(bytes_read >> 1); //transmit samples, written is an error code
|
||||
}
|
||||
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("_mic: %u , %i, %i"), millis() - __enctime, written, bytes_read);
|
||||
if(written < 0){
|
||||
break;
|
||||
}
|
||||
|
||||
// if (audio_i2s_mp3.use_stream) {
|
||||
// stack = 8000;
|
||||
// }
|
||||
if (audio_i2s_mp3.use_stream) {
|
||||
if (!audio_i2s_mp3.client.connected()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// err = xTaskCreatePinnedToCore(mic_task, "MIC", stack, NULL, 3, &audio_i2s_mp3.mic_task_handle, 1);
|
||||
audio_i2s_mp3.recdur = TasmotaGlobal.uptime - ctime;
|
||||
vTaskDelayUntil( &xLastWakeTime, pdMS_TO_TICKS(timeForOneRead));
|
||||
}
|
||||
|
||||
// return err;
|
||||
// }
|
||||
written = mic_enc->stop();
|
||||
|
||||
// void Cmd_MicRec(void) {
|
||||
if (!audio_i2s_mp3.use_stream) {
|
||||
rec_file.write(mic_enc->outFrame, written);
|
||||
} else {
|
||||
audio_i2s_mp3.client.write((const char*)mic_enc->outFrame, written);
|
||||
}
|
||||
|
||||
// if (XdrvMailbox.data_len > 0) {
|
||||
// if (!strncmp(XdrvMailbox.data, "-?", 2)) {
|
||||
// Response_P("{\"I2SREC-duration\":%d}", audio_i2s_mp3.recdur);
|
||||
// } else {
|
||||
// i2s_record_shine(XdrvMailbox.data);
|
||||
// ResponseCmndChar(XdrvMailbox.data);
|
||||
// }
|
||||
// } else {
|
||||
// if (audio_i2s_mp3.mic_task_handle) {
|
||||
// // stop task
|
||||
// audio_i2s_mp3.mic_stop = 1;
|
||||
// while (audio_i2s_mp3.mic_stop) {
|
||||
// delay(1);
|
||||
// }
|
||||
// ResponseCmndChar_P(PSTR("Stopped"));
|
||||
// }
|
||||
// }
|
||||
exit:
|
||||
delete mic_enc;
|
||||
audio_i2s_mp3.use_stream = false;
|
||||
audio_i2s.in->stopRx();
|
||||
audio_i2s_mp3.mic_stop = 0;
|
||||
audio_i2s_mp3.mic_error = error;
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("I2S: record task result code: %d, min bytes stack free: %u"), error, (uint32_t)uxTaskGetStackHighWaterMark(NULL)*4);
|
||||
audio_i2s_mp3.mic_task_handle = 0;
|
||||
audio_i2s_mp3.recdur = 0;
|
||||
audio_i2s_mp3.stream_active = false;
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
// }
|
||||
// #endif // USE_SHINE
|
||||
int32_t I2sRecord(char *path, uint32_t encoder_type) {
|
||||
esp_err_t err = ESP_OK;
|
||||
uint32_t stack = 8000;
|
||||
|
||||
#ifdef USE_I2S_MP3
|
||||
if (audio_i2s_mp3.decoder) return 0;
|
||||
#endif
|
||||
|
||||
// // mic gain in factor not percent
|
||||
// void Cmd_MicGain(void) {
|
||||
// if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 256)) {
|
||||
// if (audio_i2s.in) {
|
||||
// audio_i2s.in->setRxGain(XdrvMailbox.payload);
|
||||
// }
|
||||
// if (audio_i2s.Settings) {
|
||||
// audio_i2s.Settings->rx.gain = XdrvMailbox.payload * 16;
|
||||
// }
|
||||
// I2SSettingsSave(AUDIO_CONFIG_FILENAME);
|
||||
// }
|
||||
// ResponseCmndNumber(audio_i2s.Settings->rx.gain / 16);
|
||||
// }
|
||||
switch(encoder_type){
|
||||
#ifdef MP3_MIC_STREAM
|
||||
case MP3_ENCODER:
|
||||
switch(audio_i2s.Settings->rx.sample_rate){
|
||||
case 32000: case 48000: case 44100:
|
||||
break; // supported
|
||||
default:
|
||||
AddLog(LOG_LEVEL_ERROR, PSTR("I2S: unsupported sample rate for MP3 encoding: %d Hz"), audio_i2s.Settings->rx.sample_rate);
|
||||
return -1;
|
||||
}
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("I2S: start MP3 encoding: %d Hz"), audio_i2s.Settings->rx.sample_rate);
|
||||
break;
|
||||
#endif // MP3_MIC_STREAM
|
||||
#ifdef USE_I2S_OPUS
|
||||
case OPUS_ENCODER:
|
||||
switch(audio_i2s.Settings->rx.sample_rate){
|
||||
case 48000: case 24000: case 16000: case 12000: case 8000:
|
||||
stack = audio_i2s.Settings->rx.sample_rate/2 + 30000; //not the exact value, but okay'ish
|
||||
break;
|
||||
default:
|
||||
AddLog(LOG_LEVEL_ERROR, PSTR("I2S: unsupported sample rate for OPUS encoding: %d Hz"), audio_i2s.Settings->rx.sample_rate);
|
||||
return -1;
|
||||
}
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("I2S: start OPUS encoding: %d Hz"), audio_i2s.Settings->rx.sample_rate);
|
||||
break;
|
||||
#endif // USE_I2S_OPUS
|
||||
default:
|
||||
AddLog(LOG_LEVEL_ERROR, PSTR("I2S: unsupported encoder"));
|
||||
}
|
||||
audio_i2s_mp3.encoder_type = encoder_type;
|
||||
|
||||
if (audio_i2s_mp3.preallocateCodec != nullptr){
|
||||
AddLog(LOG_LEVEL_DEBUG,PSTR("I2S: free codec buffer"));
|
||||
free(audio_i2s_mp3.preallocateCodec);
|
||||
audio_i2s_mp3.preallocateCodec = nullptr;
|
||||
}
|
||||
|
||||
if(!audio_i2s_mp3.use_stream){
|
||||
strlcpy(audio_i2s_mp3.mic_path, path, sizeof(audio_i2s_mp3.mic_path));
|
||||
}
|
||||
audio_i2s_mp3.mic_stop = 0;
|
||||
|
||||
audio_i2s.in->startRx();
|
||||
err = xTaskCreatePinnedToCore(I2sMicTask, "MIC", stack, NULL, 3, &audio_i2s_mp3.mic_task_handle, 1);
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif // USE_I2S_AUDIO
|
||||
#endif // defined(ESP32) && ESP_IDF_VERSION_MAJOR >= 5
|
||||
|
@ -25,42 +25,57 @@
|
||||
#endif
|
||||
|
||||
|
||||
void Stream_mp3(void) {
|
||||
void I2SMP3StreamInit(){
|
||||
audio_i2s_mp3.encoder_type = MP3_ENCODER;
|
||||
I2SstreamInit ();
|
||||
}
|
||||
|
||||
void I2SOpusStreamInit(){
|
||||
audio_i2s_mp3.encoder_type = OPUS_ENCODER;
|
||||
I2SstreamInit ();
|
||||
}
|
||||
|
||||
void I2SstreamInit (void) {
|
||||
if (audio_i2s_mp3.stream_active) {
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("I2S: can not handle client - other MP3 task active"));
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("I2S: can not handle client - other stream task active"));
|
||||
return;
|
||||
}
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("I2S: Handle mp3server"));
|
||||
audio_i2s_mp3.stream_active = 1;
|
||||
audio_i2s_mp3.client = audio_i2s_mp3.MP3Server->client();
|
||||
audio_i2s_mp3.stream_active = true;
|
||||
audio_i2s_mp3.client = audio_i2s_mp3.StreamServer->client();
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("I2S: Create client"));
|
||||
// i2s_record_shine((char*)"stream.mp3");
|
||||
I2sRecordShine((char*)"stream.mp3");
|
||||
}
|
||||
|
||||
void I2sMp3Loop(void) {
|
||||
if (audio_i2s_mp3.MP3Server) {
|
||||
audio_i2s_mp3.MP3Server->handleClient();
|
||||
audio_i2s_mp3.use_stream = true;
|
||||
if(I2sRecord((char*)"", audio_i2s_mp3.encoder_type) != pdTRUE){
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("I2S: Stop client"));
|
||||
audio_i2s_mp3.stream_active = false;
|
||||
audio_i2s_mp3.client.stop();
|
||||
}
|
||||
}
|
||||
|
||||
void I2sMp3Init(uint32_t on) {
|
||||
void I2sStreamLoop(void) {
|
||||
if (audio_i2s_mp3.StreamServer) {
|
||||
audio_i2s_mp3.StreamServer->handleClient();
|
||||
}
|
||||
}
|
||||
|
||||
void I2sServerInit(uint32_t on) {
|
||||
if (on) {
|
||||
if (!audio_i2s_mp3.MP3Server) {
|
||||
audio_i2s_mp3.MP3Server = new ESP8266WebServer(MP3_STREAM_PORT);
|
||||
audio_i2s_mp3.MP3Server->on(PSTR("/stream.mp3"), Stream_mp3);
|
||||
audio_i2s_mp3.MP3Server->on(PSTR("/stream.m3a"), Stream_mp3);
|
||||
audio_i2s_mp3.MP3Server->begin();
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("MP3: server created on port: %d "), MP3_STREAM_PORT);
|
||||
if (!audio_i2s_mp3.StreamServer) {
|
||||
audio_i2s_mp3.StreamServer = new ESP8266WebServer(MP3_STREAM_PORT);
|
||||
audio_i2s_mp3.StreamServer->on(PSTR("/stream.mp3"), I2SMP3StreamInit);
|
||||
audio_i2s_mp3.StreamServer->on(PSTR("/stream.m3a"), I2SMP3StreamInit);
|
||||
audio_i2s_mp3.StreamServer->on(PSTR("/stream.webm"), I2SOpusStreamInit);
|
||||
audio_i2s_mp3.StreamServer->begin();
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("I2S: server created on port: %d "), MP3_STREAM_PORT);
|
||||
}
|
||||
} else {
|
||||
if (audio_i2s_mp3.MP3Server) {
|
||||
audio_i2s_mp3.MP3Server->stop();
|
||||
delete audio_i2s_mp3.MP3Server;
|
||||
audio_i2s_mp3.MP3Server = nullptr;
|
||||
if (audio_i2s_mp3.StreamServer) {
|
||||
audio_i2s_mp3.StreamServer->stop();
|
||||
delete audio_i2s_mp3.StreamServer;
|
||||
audio_i2s_mp3.StreamServer = nullptr;
|
||||
audio_i2s_mp3.mic_stop = 1;
|
||||
audio_i2s_mp3.stream_active = 0;
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("MP3: server deleted"));
|
||||
audio_i2s_mp3.stream_active = false;
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("I2S: server deleted"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -70,7 +85,7 @@ void CmndI2SMP3Stream(void) {
|
||||
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) {
|
||||
audio_i2s_mp3.stream_enable = XdrvMailbox.payload;
|
||||
}
|
||||
I2sMp3Init(audio_i2s_mp3.stream_enable);
|
||||
I2sServerInit(audio_i2s_mp3.stream_enable);
|
||||
ResponseCmndNumber(audio_i2s_mp3.stream_enable);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user