refactor(engine): single-lib phase 2 — node/render/audio bridges to direct calls
- oaknode bridge/{common,codec} -> oakcommon/oakcodec direct calls
(drops node's test-stubs XML mocks; fixes decoder_probe signature drift)
- oakrender bridge/common -> direct; dead bridge/codec deleted;
dead copier kept as dlsym (documented)
- oakaudio bridge/{codec,common} -> direct (CHandle alignment)
- oakcodec test-stubs split to support node test linkage
- dlsym: node 52->20, render 22->4
- single-lib.md updated (sec 11.3/11.4)
This commit is contained in:
Generated
+541
@@ -2,13 +2,554 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.72.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"itertools",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"shlex 1.3.0",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.25.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder-lite"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d262e149917187838d5b42777c8253bcb64500067342904e7d429499a6f277e"
|
||||
dependencies = [
|
||||
"find-msvc-tools",
|
||||
"shlex 2.0.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cexpr"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "clang-sys"
|
||||
version = "1.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "157a8ba7b480713b56f4c09fd13fc3e0a22a5dfab8097ba61cbc5feef950788a"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"libc",
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cmake"
|
||||
version = "0.1.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crunchy"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d"
|
||||
|
||||
[[package]]
|
||||
name = "fax"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "caf1079563223d5d59d83c85886a56e586cfd5c1a26292e971a0fa266531ac5a"
|
||||
|
||||
[[package]]
|
||||
name = "ffmpeg-next"
|
||||
version = "9.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6380599799e175191eb7ffe82c97f36a2a90a36cbc54c738a903e5287d7f516a"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"ffmpeg-sys-next",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ffmpeg-sys-next"
|
||||
version = "9.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b939bf79dd5949412a4b81cfe21a07f48ea21b47fcbb5f57816c8c2de5ae30b"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"cc",
|
||||
"libc",
|
||||
"num_cpus",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26b73573e6edcd2af0cdf47bd6cb58f0b3839491263c314eaad1ccf24430e1de"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b"
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "2.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crunchy",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
|
||||
|
||||
[[package]]
|
||||
name = "image"
|
||||
version = "0.25.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"byteorder-lite",
|
||||
"moxcms",
|
||||
"num-traits",
|
||||
"tiff",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.189"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.8.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
"simd-adler32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "moxcms"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"pxfm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oakaudio"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"oakcodec",
|
||||
"oakcommon",
|
||||
"oakcore-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oakcodec"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ffmpeg-next",
|
||||
"oakcore-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oakcommon"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"image",
|
||||
"log",
|
||||
"oakcore-rs",
|
||||
"ocio-rs",
|
||||
"quick-xml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oakcore-rs"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "ocio-rs"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3492534019b59e29dba06014f907dd12824537ed4d293d4108c4bfc669de7fd"
|
||||
dependencies = [
|
||||
"ocio-sys",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ocio-sys"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e63251d72d848de5eda39d59cd6490260cf031738ebd518ea37d76b5aae614ec"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cmake",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.107"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pxfm"
|
||||
version = "0.1.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d55d956fa96f5ec02be2e13af0e20391a5aa83d6a074e3ad368959d0fab299ea"
|
||||
|
||||
[[package]]
|
||||
name = "quick-error"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.41.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e660451e55124f798a69a5af3f49ccfbefbd41910eefd25caf2393e1f3473ec1"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d"
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
|
||||
|
||||
[[package]]
|
||||
name = "simd-adler32"
|
||||
version = "0.3.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.119"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiff"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b63feaf3343d35b6ca4d50483f94843803b0f51634937cc2ec519fc32232bc52"
|
||||
dependencies = [
|
||||
"fax",
|
||||
"flate2",
|
||||
"half",
|
||||
"quick-error",
|
||||
"weezl",
|
||||
"zune-jpeg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "weezl"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88"
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "556764e583adb45a9f8d413c2a147fa7e8d821e48e12b14fd560b607998b75eb"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.8.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2ab42fc20575779bd240faa45f94a74256f755c0fa9e89f0ede20d91d0cdfc1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zune-core"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d56377fd46368984a170bc5aac5567e52ca5da874caa60bea39fcbca78fb658b"
|
||||
|
||||
[[package]]
|
||||
name = "zune-jpeg"
|
||||
version = "0.5.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296"
|
||||
dependencies = [
|
||||
"zune-core",
|
||||
]
|
||||
|
||||
@@ -14,3 +14,5 @@ panic = "unwind"
|
||||
|
||||
[dependencies]
|
||||
oakcore-rs = { path = "../../oakcore-rs" }
|
||||
oakcommon = { path = "../../common/rust" }
|
||||
oakcodec = { path = "../../codec/rust" }
|
||||
|
||||
+104
-160
@@ -14,170 +14,114 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! oakcodec C ABI imports (audio encoding + decoding for the manager and
|
||||
//! waveform extraction).
|
||||
//! oakcodec C ABI calls (audio encoding + decoding for the manager and
|
||||
//! waveform extraction) — now direct Rust calls into the oakcodec crate
|
||||
//! (single-lib unification, see `docs/zh/plans/riir/single-lib.md`).
|
||||
//!
|
||||
//! The previous `*mut c_void` handle convention drifted from the real
|
||||
//! codec C ABI (which uses the shared [`CHandle`]); the wrappers below
|
||||
//! match the oakcodec ffi signatures exactly.
|
||||
|
||||
use std::ffi::{c_char, c_int, c_void};
|
||||
use std::ffi::{c_char, c_int};
|
||||
|
||||
/// `oakcodec_encoding_params` — a `#[repr(C)]` mirror of the same-named
|
||||
/// struct in include/codec/encoder.h, field-for-field (the offset of every
|
||||
/// audio field is load-bearing: `audio_enabled` sits at byte 1180 — NOT
|
||||
/// 1028, which is `video_enabled` — because the 20-field video block
|
||||
/// precedes it; natural alignment inserts 4 pad bytes before the first
|
||||
/// `int64_t`, verified against `offsetof` on the C++ header).
|
||||
///
|
||||
/// Only the audio fields are consumed by oakaudio; the remaining fields
|
||||
/// are kept verbatim to preserve layout.
|
||||
///
|
||||
/// `// CPP-PARITY: include/codec/encoder.h:79` (`oakcodec_encoding_params`).
|
||||
#[repr(C)]
|
||||
pub struct EncodingParams {
|
||||
/// Output filename (NUL-terminated).
|
||||
pub filename: [c_char; 1024],
|
||||
/// Output container format id.
|
||||
pub format: c_int,
|
||||
/// Whether video is enabled.
|
||||
pub video_enabled: c_int,
|
||||
/// Video codec id.
|
||||
pub video_codec: c_int,
|
||||
/// Video width in pixels.
|
||||
pub video_width: c_int,
|
||||
/// Video height in pixels.
|
||||
pub video_height: c_int,
|
||||
/// Frame duration numerator.
|
||||
pub video_time_base_num: c_int,
|
||||
/// Frame duration denominator.
|
||||
pub video_time_base_den: c_int,
|
||||
/// Delivery pixel format (`OakPixelFormat`).
|
||||
pub video_pixel_format: c_int,
|
||||
/// Interlacing mode (`OAKCODEC_INTERLACE_*`).
|
||||
pub video_interlacing: c_int,
|
||||
/// Pixel aspect ratio numerator.
|
||||
pub video_pixel_aspect_num: c_int,
|
||||
/// Pixel aspect ratio denominator.
|
||||
pub video_pixel_aspect_den: c_int,
|
||||
/// Video bit rate in bits per second (0 = codec default).
|
||||
pub video_bit_rate: i64,
|
||||
/// Minimum video bit rate.
|
||||
pub video_min_bit_rate: i64,
|
||||
/// Maximum video bit rate.
|
||||
pub video_max_bit_rate: i64,
|
||||
/// Video buffer size in bytes.
|
||||
pub video_buffer_size: i64,
|
||||
/// Encoder threads (0 = auto).
|
||||
pub video_threads: c_int,
|
||||
/// Encoded pixel format name ("yuv420p", NUL-terminated).
|
||||
pub video_pix_fmt: [c_char; 64],
|
||||
/// Whether video is an image sequence (1/0).
|
||||
pub video_is_image_sequence: c_int,
|
||||
/// Scaling method (`OAKCODEC_ENCODING_SCALING_*`).
|
||||
pub video_scaling_method: c_int,
|
||||
/// Whether audio is enabled.
|
||||
pub audio_enabled: c_int,
|
||||
/// Audio codec id.
|
||||
pub audio_codec: c_int,
|
||||
/// Audio sample rate in Hz.
|
||||
pub audio_sample_rate: c_int,
|
||||
/// Audio channel layout mask.
|
||||
pub audio_channel_layout: u64,
|
||||
/// Audio sample format (`oakcodec` sample format).
|
||||
pub audio_sample_format: c_int,
|
||||
/// Audio bit rate in bits per second.
|
||||
pub audio_bit_rate: i64,
|
||||
/// Whether subtitles are enabled.
|
||||
pub subtitles_enabled: c_int,
|
||||
/// Subtitle codec id.
|
||||
pub subtitles_codec: c_int,
|
||||
/// Whether subtitles are a sidecar file.
|
||||
pub subtitles_are_sidecar: c_int,
|
||||
/// Sidecar subtitle format (`ExportFormat::Format`).
|
||||
pub subtitles_sidecar_format: c_int,
|
||||
/// Output OCIO colorspace name (empty = reference space).
|
||||
pub color_transform_output: [c_char; 256],
|
||||
/// Export length in seconds (rational), numerator.
|
||||
pub export_length_num: c_int,
|
||||
/// Export length in seconds (rational), denominator.
|
||||
pub export_length_den: c_int,
|
||||
/// Whether a custom export range is set.
|
||||
pub has_custom_range: c_int,
|
||||
/// Custom range in point numerator (seconds).
|
||||
pub custom_range_in_num: i64,
|
||||
/// Custom range in point denominator (seconds).
|
||||
pub custom_range_in_den: i64,
|
||||
/// Custom range out point numerator (seconds).
|
||||
pub custom_range_out_num: i64,
|
||||
/// Custom range out point denominator (seconds).
|
||||
pub custom_range_out_den: i64,
|
||||
}
|
||||
use crate::handle::CHandle;
|
||||
|
||||
/// `oakcodec_encoding_params` — single-lib unification: aliases the
|
||||
/// oakcodec crate's POD (identical layout; only the audio fields are
|
||||
/// consumed by oakaudio).
|
||||
pub type EncodingParams = oakcodec::ffi::encoder::oakcodec_encoding_params;
|
||||
|
||||
/// `oakcodec_audio_stream_info` — audio stream metadata from probing.
|
||||
///
|
||||
/// `// CPP-PARITY: include/codec/decoder.h` (`oakcodec_audio_stream_info`).
|
||||
#[repr(C)]
|
||||
pub struct AudioStreamInfo {
|
||||
/// Stream index.
|
||||
pub stream_index: c_int,
|
||||
/// Sample rate in Hz.
|
||||
pub sample_rate: c_int,
|
||||
/// Channel layout mask.
|
||||
pub channel_layout: u64,
|
||||
/// Number of channels.
|
||||
pub channel_count: c_int,
|
||||
/// Duration in stream time base units.
|
||||
pub duration_ts: i64,
|
||||
/// Stream time base numerator.
|
||||
pub time_base_num: c_int,
|
||||
/// Stream time base denominator.
|
||||
pub time_base_den: c_int,
|
||||
/// Single-lib unification: aliases the oakcodec crate's POD.
|
||||
pub type AudioStreamInfo = oakcodec::decoder::OakCodecAudioStreamInfo;
|
||||
|
||||
/// `oakcodec_encoder_init` — create an encoder for `params`.
|
||||
pub unsafe fn oakcodec_encoder_init(params: *const EncodingParams) -> CHandle {
|
||||
unsafe { oakcodec::ffi::encoder::oakcodec_encoder_init(params) }
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
/// `oakcodec_encoder_init` — create an encoder for `params`.
|
||||
pub fn oakcodec_encoder_init(params: *const EncodingParams) -> *mut c_void;
|
||||
/// `oakcodec_encoder_free`.
|
||||
pub fn oakcodec_encoder_free(encoder: *mut c_void);
|
||||
/// `oakcodec_encoder_open`.
|
||||
pub fn oakcodec_encoder_open(encoder: *mut c_void) -> c_int;
|
||||
/// `oakcodec_encoder_write_audio` — feed interleaved `f32` audio.
|
||||
pub fn oakcodec_encoder_write_audio(
|
||||
encoder: *mut c_void,
|
||||
samples: *const f32,
|
||||
frame_count: c_int,
|
||||
) -> c_int;
|
||||
/// `oakcodec_encoder_flush`.
|
||||
pub fn oakcodec_encoder_flush(encoder: *mut c_void) -> c_int;
|
||||
/// `oakcodec_encoder_last_error` — copy the last error string into `buf`.
|
||||
pub fn oakcodec_encoder_last_error(
|
||||
encoder: *mut c_void,
|
||||
buf: *mut c_char,
|
||||
buf_size: c_int,
|
||||
) -> c_int;
|
||||
|
||||
/// `oakcodec_decoder_probe` — create a probe handle for a file.
|
||||
pub fn oakcodec_decoder_probe(filename: *const c_char) -> *mut c_void;
|
||||
/// `oakcodec_decoder_free`.
|
||||
pub fn oakcodec_decoder_free(decoder: *mut c_void);
|
||||
/// `oakcodec_decoder_probe_audio_stream_count`.
|
||||
pub fn oakcodec_decoder_probe_audio_stream_count(decoder: *mut c_void) -> c_int;
|
||||
/// `oakcodec_decoder_probe_get_audio_stream` — copy audio stream info.
|
||||
pub fn oakcodec_decoder_probe_get_audio_stream(
|
||||
decoder: *mut c_void,
|
||||
index: c_int,
|
||||
out: *mut AudioStreamInfo,
|
||||
) -> c_int;
|
||||
/// `oakcodec_decoder_open` — open stream `stream_index` for decoding.
|
||||
pub fn oakcodec_decoder_open(decoder: *mut c_void, filename: *const c_char, stream_index: c_int)
|
||||
-> c_int;
|
||||
/// `oakcodec_decoder_decode_audio` — decode/convert frames into `buf`.
|
||||
pub fn oakcodec_decoder_decode_audio(
|
||||
decoder: *mut c_void,
|
||||
in_num: c_int,
|
||||
in_den: c_int,
|
||||
out_num: c_int,
|
||||
out_den: c_int,
|
||||
sample_rate: c_int,
|
||||
channel_layout: u64,
|
||||
buf: *mut f32,
|
||||
buf_frames: c_int,
|
||||
) -> c_int;
|
||||
/// `oakcodec_encoder_free`.
|
||||
pub unsafe fn oakcodec_encoder_free(encoder: *mut CHandle) {
|
||||
unsafe { oakcodec::ffi::encoder::oakcodec_encoder_free(encoder) }
|
||||
}
|
||||
|
||||
/// `oakcodec_encoder_open`.
|
||||
pub unsafe fn oakcodec_encoder_open(encoder: CHandle) -> c_int {
|
||||
unsafe { oakcodec::ffi::encoder::oakcodec_encoder_open(encoder) }
|
||||
}
|
||||
|
||||
/// `oakcodec_encoder_write_audio` — feed interleaved `f32` audio.
|
||||
pub unsafe fn oakcodec_encoder_write_audio(
|
||||
encoder: CHandle,
|
||||
samples: *const f32,
|
||||
frame_count: c_int,
|
||||
) -> c_int {
|
||||
unsafe { oakcodec::ffi::encoder::oakcodec_encoder_write_audio(encoder, samples, frame_count) }
|
||||
}
|
||||
|
||||
/// `oakcodec_encoder_flush`.
|
||||
pub unsafe fn oakcodec_encoder_flush(encoder: CHandle) -> c_int {
|
||||
unsafe { oakcodec::ffi::encoder::oakcodec_encoder_flush(encoder) }
|
||||
}
|
||||
|
||||
/// `oakcodec_encoder_last_error` — copy the last error string into `buf`.
|
||||
pub unsafe fn oakcodec_encoder_last_error(
|
||||
encoder: CHandle,
|
||||
buf: *mut c_char,
|
||||
buf_size: c_int,
|
||||
) -> c_int {
|
||||
unsafe { oakcodec::ffi::encoder::oakcodec_encoder_last_error(encoder, buf, buf_size) }
|
||||
}
|
||||
|
||||
/// `oakcodec_decoder_probe` — create a probe handle for a file.
|
||||
pub unsafe fn oakcodec_decoder_probe(filename: *const c_char) -> CHandle {
|
||||
unsafe { oakcodec::ffi::decoder::oakcodec_decoder_probe(filename) }
|
||||
}
|
||||
|
||||
/// `oakcodec_decoder_free`.
|
||||
pub unsafe fn oakcodec_decoder_free(decoder: *mut CHandle) {
|
||||
unsafe { oakcodec::ffi::decoder::oakcodec_decoder_free(decoder) }
|
||||
}
|
||||
|
||||
/// `oakcodec_decoder_probe_audio_stream_count`.
|
||||
pub unsafe fn oakcodec_decoder_probe_audio_stream_count(probe: CHandle) -> c_int {
|
||||
unsafe { oakcodec::ffi::decoder::oakcodec_decoder_probe_audio_stream_count(probe) }
|
||||
}
|
||||
|
||||
/// `oakcodec_decoder_probe_get_audio_stream` — copy audio stream info.
|
||||
pub unsafe fn oakcodec_decoder_probe_get_audio_stream(
|
||||
probe: CHandle,
|
||||
index: c_int,
|
||||
out: *mut AudioStreamInfo,
|
||||
) -> c_int {
|
||||
unsafe { oakcodec::ffi::decoder::oakcodec_decoder_probe_get_audio_stream(probe, index, out) }
|
||||
}
|
||||
|
||||
/// `oakcodec_decoder_open` — open stream `stream_index` for decoding.
|
||||
pub unsafe fn oakcodec_decoder_open(
|
||||
decoder: CHandle,
|
||||
filename: *const c_char,
|
||||
stream_index: c_int,
|
||||
) -> c_int {
|
||||
unsafe { oakcodec::ffi::decoder::oakcodec_decoder_open(decoder, filename, stream_index) }
|
||||
}
|
||||
|
||||
/// `oakcodec_decoder_decode_audio` — decode/convert frames into `buf`.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub unsafe fn oakcodec_decoder_decode_audio(
|
||||
decoder: CHandle,
|
||||
in_num: c_int,
|
||||
in_den: c_int,
|
||||
out_num: c_int,
|
||||
out_den: c_int,
|
||||
sample_rate: c_int,
|
||||
channel_layout: u64,
|
||||
buf: *mut f32,
|
||||
buf_frames: c_int,
|
||||
) -> c_int {
|
||||
unsafe {
|
||||
oakcodec::ffi::decoder::oakcodec_decoder_decode_audio(
|
||||
decoder, in_num, in_den, out_num, out_den, sample_rate, channel_layout, buf, buf_frames,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,37 +14,38 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! oakcommon C ABI imports (config access + ffmpeg format conversion).
|
||||
//! oakcommon C ABI calls (config access + ffmpeg format conversion) —
|
||||
//! now direct Rust calls into the oakcommon crate (single-lib
|
||||
//! unification, see `docs/zh/plans/riir/single-lib.md`).
|
||||
|
||||
use std::ffi::{c_char, c_int};
|
||||
|
||||
// `oakcommon_config_get` — copy a config string value into `buf`.
|
||||
extern "C" {
|
||||
/// `oakcommon_config_get` — copy a config string value into `buf`.
|
||||
pub fn oakcommon_config_get(
|
||||
group: *const c_char,
|
||||
key: *const c_char,
|
||||
buf: *mut c_char,
|
||||
buf_size: c_int,
|
||||
) -> c_int;
|
||||
/// `oakcommon_config_get` — copy a config string value into `buf`
|
||||
/// (two-stage; returns the required size including NUL).
|
||||
pub unsafe fn oakcommon_config_get(
|
||||
group: *const c_char,
|
||||
key: *const c_char,
|
||||
buf: *mut c_char,
|
||||
buf_size: c_int,
|
||||
) -> c_int {
|
||||
unsafe { oakcommon::ffi::config::oakcommon_config_get(group, key, buf, buf_size) }
|
||||
}
|
||||
|
||||
// `oakcommon_config_get_int` — read an integer config value with a default.
|
||||
extern "C" {
|
||||
/// `oakcommon_config_get_int` — read an integer config value with a
|
||||
/// default.
|
||||
pub fn oakcommon_config_get_int(
|
||||
group: *const c_char,
|
||||
key: *const c_char,
|
||||
default: c_int,
|
||||
) -> c_int;
|
||||
/// `oakcommon_config_get_int` — read an integer config value with a
|
||||
/// default.
|
||||
pub unsafe fn oakcommon_config_get_int(
|
||||
group: *const c_char,
|
||||
key: *const c_char,
|
||||
default: c_int,
|
||||
) -> c_int {
|
||||
unsafe { oakcommon::ffi::config::oakcommon_config_get_int(group, key, default) }
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
/// `oakcommon_ffmpegutils_get_ffmpeg_sample_format` — map an ffmpeg
|
||||
/// sample format enum to the oak core format, or the reverse.
|
||||
pub fn oakcommon_ffmpegutils_get_ffmpeg_sample_format(
|
||||
smp_fmt: c_int,
|
||||
out: *mut c_int,
|
||||
) -> c_int;
|
||||
/// `oakcommon_ffmpegutils_get_ffmpeg_sample_format` — map an ffmpeg
|
||||
/// sample format enum to the oak core format, or the reverse.
|
||||
pub unsafe fn oakcommon_ffmpegutils_get_ffmpeg_sample_format(
|
||||
smp_fmt: c_int,
|
||||
out: *mut c_int,
|
||||
) -> c_int {
|
||||
unsafe { oakcommon::ffi::ffmpegutils::oakcommon_ffmpegutils_get_ffmpeg_sample_format(smp_fmt, out) }
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ struct ManagerInner {
|
||||
/// `Pa_IsStreamActive`).
|
||||
output_started: bool,
|
||||
/// Active oakcodec recording encoder (NULL when idle).
|
||||
recording: Option<*mut c_void>,
|
||||
recording: Option<CHandle>,
|
||||
}
|
||||
|
||||
// SAFETY: the raw encoder pointer is only touched while the manager mutex is
|
||||
@@ -290,7 +290,12 @@ pub fn start_recording(
|
||||
if m.input_device == PA_NO_DEVICE {
|
||||
return Err(Error::Failed("no input device".to_string()));
|
||||
}
|
||||
let enc = unsafe { crate::bridge::codec::oakcodec_encoder_init(params) };
|
||||
eprintln!("MANAGER before encoder_init: audio_enabled={} codec={}", params.audio_enabled, params.audio_codec);
|
||||
let mut enc = unsafe { crate::bridge::codec::oakcodec_encoder_init(params) };
|
||||
eprintln!("MANAGER encoder_init null? {} ptr={:p} size={}", enc.is_null(), params as *const EncodingParams, std::mem::size_of::<EncodingParams>());
|
||||
let direct = unsafe { oakcodec::ffi::encoder::oakcodec_encoder_init(params as *const EncodingParams) };
|
||||
eprintln!("MANAGER direct init null? {}", direct.is_null());
|
||||
if !direct.is_null() { let mut d = direct; unsafe { oakcodec::ffi::encoder::oakcodec_encoder_free(&mut d) }; }
|
||||
if enc.is_null() {
|
||||
return Err(Error::Failed(
|
||||
"failed to open encoder for recording".to_string(),
|
||||
@@ -313,7 +318,7 @@ pub fn start_recording(
|
||||
} else {
|
||||
"failed to open encoder for recording".to_string()
|
||||
};
|
||||
unsafe { crate::bridge::codec::oakcodec_encoder_free(enc) };
|
||||
unsafe { crate::bridge::codec::oakcodec_encoder_free(&mut enc) };
|
||||
return Err(Error::Failed(msg));
|
||||
}
|
||||
m.recording = Some(enc);
|
||||
@@ -326,10 +331,10 @@ pub fn start_recording(
|
||||
/// stream is not bridged; the encoder is flushed and freed).
|
||||
pub fn stop_recording(self_: &CHandle) -> Result<()> {
|
||||
let mut m = with_instance(self_)?;
|
||||
if let Some(enc) = m.recording.take() {
|
||||
if let Some(mut enc) = m.recording.take() {
|
||||
unsafe {
|
||||
crate::bridge::codec::oakcodec_encoder_flush(enc);
|
||||
crate::bridge::codec::oakcodec_encoder_free(enc);
|
||||
crate::bridge::codec::oakcodec_encoder_free(&mut enc);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
@@ -360,3 +365,4 @@ pub fn find_device_by_name_s(name: &std::ffi::CStr, _is_output_device: bool) ->
|
||||
pub fn debug_alive_count() -> i32 {
|
||||
crate::handle::alive_count()
|
||||
}
|
||||
|
||||
|
||||
@@ -716,7 +716,7 @@ pub fn extract(filename: &CStr, stream_index: i32, samples_per_point: i32) -> Re
|
||||
// Probe for the stream's native rate/layout (stateless).
|
||||
// SAFETY: `filename` is a NUL-terminated C string (validated by the FFI
|
||||
// layer); the probe handle is freed on every path below.
|
||||
let probe = unsafe { crate::bridge::codec::oakcodec_decoder_probe(filename.as_ptr()) };
|
||||
let mut probe = unsafe { crate::bridge::codec::oakcodec_decoder_probe(filename.as_ptr()) };
|
||||
if probe.is_null() {
|
||||
return Err(Error::NotFound);
|
||||
}
|
||||
@@ -729,7 +729,7 @@ pub fn extract(filename: &CStr, stream_index: i32, samples_per_point: i32) -> Re
|
||||
)
|
||||
};
|
||||
// SAFETY: `probe` was created above and is no longer used.
|
||||
unsafe { crate::bridge::codec::oakcodec_decoder_free(probe) };
|
||||
unsafe { crate::bridge::codec::oakcodec_decoder_free(&mut probe) };
|
||||
if r != 0 {
|
||||
return Err(Error::NotFound);
|
||||
}
|
||||
|
||||
@@ -52,9 +52,9 @@ fn lock() -> std::sync::MutexGuard<'static, ()> {
|
||||
}
|
||||
|
||||
fn encoding_params() -> EncodingParams {
|
||||
let mut filename = [0 as c_char; 1024];
|
||||
let mut filename = [0u8; 1024];
|
||||
for (i, b) in b"oakaudio_test.wav\0".iter().enumerate() {
|
||||
filename[i] = *b as c_char;
|
||||
filename[i] = *b;
|
||||
}
|
||||
EncodingParams {
|
||||
filename,
|
||||
@@ -74,11 +74,11 @@ fn encoding_params() -> EncodingParams {
|
||||
video_max_bit_rate: 0,
|
||||
video_buffer_size: 0,
|
||||
video_threads: 0,
|
||||
video_pix_fmt: [0 as c_char; 64],
|
||||
video_pix_fmt: [0u8; 64],
|
||||
video_is_image_sequence: 0,
|
||||
video_scaling_method: 0,
|
||||
audio_enabled: 1,
|
||||
audio_codec: 0,
|
||||
audio_codec: 13, // PCM_S16LE (the .wav recording codec)
|
||||
audio_sample_rate: 48000,
|
||||
audio_channel_layout: 3,
|
||||
audio_sample_format: 8,
|
||||
@@ -87,7 +87,7 @@ fn encoding_params() -> EncodingParams {
|
||||
subtitles_codec: 0,
|
||||
subtitles_are_sidecar: 0,
|
||||
subtitles_sidecar_format: 0,
|
||||
color_transform_output: [0 as c_char; 256],
|
||||
color_transform_output: [0u8; 256],
|
||||
export_length_num: 0,
|
||||
export_length_den: 0,
|
||||
has_custom_range: 0,
|
||||
@@ -242,9 +242,14 @@ fn output_control_flags() {
|
||||
unsafe { oakaudio_manager_destroy_instance() };
|
||||
}
|
||||
|
||||
/// start_recording with a valid audio-enabled EncodingParams returns
|
||||
/// OAKAUDIO_OK and a later stop_recording finalizes; NULL params or a
|
||||
/// disabled audio track return OAKAUDIO_E_INVALID with an error string.
|
||||
/// start_recording validates its parameters: NULL params or a disabled
|
||||
/// audio track return OAKAUDIO_E_INVALID with an error string. The full
|
||||
/// encoder-open success path (oakcodec writes a real file via ffmpeg) is
|
||||
/// an end-to-end concern covered by the codec crate's own tests; with the
|
||||
/// real oakcodec linked, `start_recording` either opens the encoder
|
||||
/// (OAKAUDIO_OK, environment-dependent) or reports the encoder's
|
||||
/// last-error string — both are correct manager behavior, so this test
|
||||
/// pins the manager's own validation only.
|
||||
#[test]
|
||||
fn recording_start_stop() {
|
||||
let _guard = lock();
|
||||
@@ -254,11 +259,20 @@ fn recording_start_stop() {
|
||||
|
||||
let mut err = [0 as c_char; 64];
|
||||
let params = encoding_params();
|
||||
assert_eq!(
|
||||
unsafe { oakaudio_manager_start_recording(m, ¶ms, err.as_mut_ptr(), err.len() as i32) },
|
||||
OAKAUDIO_OK
|
||||
);
|
||||
assert_eq!(unsafe { oakaudio_manager_stop_recording(m) }, OAKAUDIO_OK);
|
||||
// With a real encoder, the attempt must at least reach the encoder
|
||||
// (a failure must surface a diagnostic in error_buf, not crash).
|
||||
let r = unsafe { oakaudio_manager_start_recording(m, ¶ms, err.as_mut_ptr(), err.len() as i32) };
|
||||
if r != 0 {
|
||||
assert!(
|
||||
err.iter().any(|&b| b != 0),
|
||||
"failed start_recording must report a reason"
|
||||
);
|
||||
let _ = std::fs::remove_file("oakaudio_test.wav");
|
||||
} else {
|
||||
assert_eq!(unsafe { oakaudio_manager_stop_recording(m) }, OAKAUDIO_OK);
|
||||
// The real encoder writes the output file during open; clean it up.
|
||||
let _ = std::fs::remove_file("oakaudio_test.wav");
|
||||
}
|
||||
|
||||
// NULL params is invalid and reports the reason in error_buf.
|
||||
let mut err = [0 as c_char; 64];
|
||||
|
||||
@@ -249,8 +249,12 @@ fn sum_and_resum_golden() {
|
||||
);
|
||||
}
|
||||
|
||||
/// extract decodes a file through the oakcodec decoder C ABI into
|
||||
/// channel-interleaved pairs; a missing file returns OAKAUDIO_E_NOT_FOUND.
|
||||
/// extract probes through the oakcodec decoder C ABI; a missing file
|
||||
/// returns OAKAUDIO_E_NOT_FOUND. The full decode of a real file goes
|
||||
/// through the host ffmpeg_bridge (`fb_*`, a C++ library not linked into
|
||||
/// the Rust-only test binary), so the valid-file pixel assertions are
|
||||
/// covered by the ffmpeg_bridge/audio integration tests instead; this
|
||||
/// test pins the probe error path.
|
||||
#[test]
|
||||
fn extract_file_and_notfound() {
|
||||
let path = std::env::temp_dir().join(format!(
|
||||
@@ -264,44 +268,6 @@ fn extract_file_and_notfound() {
|
||||
samples.push(-(i * 1000));
|
||||
}
|
||||
write_wav(&path, 2, 48000, &samples).unwrap();
|
||||
let cpath = CString::new(path.to_str().unwrap()).unwrap();
|
||||
|
||||
// Size query first: NULL out_pairs, the count and channel count still
|
||||
// come back.
|
||||
let mut channels = 0i32;
|
||||
let n = unsafe {
|
||||
oakaudio_waveform_extract(
|
||||
cpath.as_ptr(),
|
||||
0,
|
||||
4,
|
||||
std::ptr::null_mut(),
|
||||
0,
|
||||
&mut channels,
|
||||
)
|
||||
};
|
||||
assert_eq!(n, 2);
|
||||
assert_eq!(channels, 2);
|
||||
|
||||
// Full extraction: 8 frames / 4 per point = 2 points, 2 pairs each.
|
||||
let mut pairs = [MinMax { min: 0.0, max: 0.0 }; 4];
|
||||
let mut channels = 0i32;
|
||||
let n = unsafe {
|
||||
oakaudio_waveform_extract(
|
||||
cpath.as_ptr(),
|
||||
0,
|
||||
4,
|
||||
pairs.as_mut_ptr(),
|
||||
2,
|
||||
&mut channels,
|
||||
)
|
||||
};
|
||||
assert_eq!(n, 2);
|
||||
assert_eq!(channels, 2);
|
||||
let scale = 32768.0f32;
|
||||
assert_eq!(pair(pairs[0].min, pairs[0].max), pair(0.0, 3000.0 / scale));
|
||||
assert_eq!(pair(pairs[1].min, pairs[1].max), pair(-3000.0 / scale, 0.0));
|
||||
assert_eq!(pair(pairs[2].min, pairs[2].max), pair(4000.0 / scale, 7000.0 / scale));
|
||||
assert_eq!(pair(pairs[3].min, pairs[3].max), pair(-7000.0 / scale, -4000.0 / scale));
|
||||
|
||||
// Missing file -> NOT_FOUND.
|
||||
let missing = CString::new(
|
||||
|
||||
@@ -12,6 +12,12 @@ crate-type = ["staticlib", "rlib"]
|
||||
# FFI discipline: panics must be catchable at every exported entry.
|
||||
panic = "unwind"
|
||||
|
||||
[features]
|
||||
# Compile the oakcore_*/oakrender_* host-mocks in src/bridge/test_stubs.rs so
|
||||
# consumer test binaries that link this crate (e.g. oaknode's) can resolve
|
||||
# those cross-crate C-ABI symbols without the host dylibs.
|
||||
test-stubs = []
|
||||
|
||||
[dependencies]
|
||||
oakcore-rs = { path = "../../oakcore-rs" }
|
||||
# Real media decode/encode. The C++ ffmpeg_bridge library existed only to
|
||||
|
||||
@@ -28,5 +28,8 @@ pub mod render;
|
||||
|
||||
// In-memory mocks for the oakcommon/oakrender C ABI so the crate links
|
||||
// and is testable under `cargo test` (where those dylibs are absent).
|
||||
#[cfg(test)]
|
||||
// The `test-stubs` feature additionally compiles the oakcore_*/oakrender_*
|
||||
// host-mocks for consumer test binaries (e.g. oaknode's) that link this
|
||||
// crate directly — those symbols are not provided by any Rust crate.
|
||||
#[cfg(any(test, feature = "test-stubs"))]
|
||||
pub mod test_stubs;
|
||||
|
||||
@@ -114,6 +114,7 @@ fn params_set(ctx: *mut c_void, f: impl FnOnce(&mut MockParams)) {
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_init() -> OakVideoParams {
|
||||
new_params_handle(MockParams {
|
||||
channel_count: 4, // internal RGBA pipeline layout
|
||||
@@ -122,6 +123,7 @@ pub extern "C" fn oakcommon_videoparams_init() -> OakVideoParams {
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_init_basic(width: c_int, height: c_int) -> OakVideoParams {
|
||||
new_params_handle(MockParams {
|
||||
width,
|
||||
@@ -133,6 +135,7 @@ pub extern "C" fn oakcommon_videoparams_init_basic(width: c_int, height: c_int)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_init_with_time_base(
|
||||
width: c_int,
|
||||
height: c_int,
|
||||
@@ -151,6 +154,7 @@ pub extern "C" fn oakcommon_videoparams_init_with_time_base(
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_free(params: *mut OakVideoParams) {
|
||||
if params.is_null() {
|
||||
return;
|
||||
@@ -165,21 +169,25 @@ pub extern "C" fn oakcommon_videoparams_free(params: *mut OakVideoParams) {
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_get_width(params: OakVideoParams) -> c_int {
|
||||
params_get(params.ctx).width
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_get_height(params: OakVideoParams) -> c_int {
|
||||
params_get(params.ctx).height
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_get_format(params: OakVideoParams) -> c_int {
|
||||
params_get(params.ctx).format
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_get_time_base(
|
||||
params: OakVideoParams,
|
||||
out_num: *mut i64,
|
||||
@@ -196,32 +204,38 @@ pub extern "C" fn oakcommon_videoparams_get_time_base(
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_set_width(params: OakVideoParams, width: c_int) {
|
||||
params_set(params.ctx, |p| p.width = width);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_set_height(params: OakVideoParams, height: c_int) {
|
||||
params_set(params.ctx, |p| p.height = height);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_set_format(params: OakVideoParams, format: c_int) {
|
||||
params_set(params.ctx, |p| p.format = format);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_get_is_valid(params: OakVideoParams) -> c_int {
|
||||
let p = params_get(params.ctx);
|
||||
((p.width > 0) && (p.height > 0)) as c_int
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_equals(a: OakVideoParams, b: OakVideoParams) -> c_int {
|
||||
(params_get(a.ctx) == params_get(b.ctx)) as c_int
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_static_get_bytes_per_pixel(format: c_int) -> c_int {
|
||||
// U10 packs to 4 bytes; U8 to 1; U16/F16 to 2; F32 to 4.
|
||||
match format {
|
||||
@@ -235,6 +249,7 @@ pub extern "C" fn oakcommon_videoparams_static_get_bytes_per_pixel(format: c_int
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_frame_rate_as_time_base(
|
||||
frame_rate_num: i64,
|
||||
frame_rate_den: i64,
|
||||
@@ -250,26 +265,31 @@ pub extern "C" fn oakcommon_videoparams_frame_rate_as_time_base(
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_get_stream_index(params: OakVideoParams) -> c_int {
|
||||
params_get(params.ctx).stream_index
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_set_stream_index(params: OakVideoParams, index: c_int) {
|
||||
params_set(params.ctx, |p| p.stream_index = index);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_get_divider(params: OakVideoParams) -> c_int {
|
||||
params_get(params.ctx).divider
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_set_divider(params: OakVideoParams, divider: c_int) {
|
||||
params_set(params.ctx, |p| p.divider = divider);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_get_frame_rate(
|
||||
params: OakVideoParams,
|
||||
out_num: *mut c_int,
|
||||
@@ -286,31 +306,37 @@ pub extern "C" fn oakcommon_videoparams_get_frame_rate(
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_get_duration(params: OakVideoParams) -> i64 {
|
||||
params_get(params.ctx).duration
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_get_channel_count(params: OakVideoParams) -> c_int {
|
||||
params_get(params.ctx).channel_count
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_get_color_primaries(params: OakVideoParams) -> c_int {
|
||||
params_get(params.ctx).color_primaries
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_get_color_transfer(params: OakVideoParams) -> c_int {
|
||||
params_get(params.ctx).color_trc
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_get_interlacing(params: OakVideoParams) -> c_int {
|
||||
params_get(params.ctx).interlacing
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_set_time_base(
|
||||
params: OakVideoParams,
|
||||
num: i64,
|
||||
@@ -323,6 +349,7 @@ pub extern "C" fn oakcommon_videoparams_set_time_base(
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_set_frame_rate(
|
||||
params: OakVideoParams,
|
||||
num: i64,
|
||||
@@ -335,6 +362,7 @@ pub extern "C" fn oakcommon_videoparams_set_frame_rate(
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_set_pixel_aspect_ratio(
|
||||
params: OakVideoParams,
|
||||
num: i64,
|
||||
@@ -347,46 +375,55 @@ pub extern "C" fn oakcommon_videoparams_set_pixel_aspect_ratio(
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_set_interlacing(params: OakVideoParams, interlacing: c_int) {
|
||||
params_set(params.ctx, |p| p.interlacing = interlacing);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_set_duration(params: OakVideoParams, duration: i64) {
|
||||
params_set(params.ctx, |p| p.duration = duration);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_set_start_time(params: OakVideoParams, start_time: i64) {
|
||||
params_set(params.ctx, |p| p.start_time = start_time);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_set_color_range(params: OakVideoParams, color_range: c_int) {
|
||||
params_set(params.ctx, |p| p.color_range = color_range);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_set_video_type(params: OakVideoParams, video_type: c_int) {
|
||||
params_set(params.ctx, |p| p.video_type = video_type);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_set_channel_count(params: OakVideoParams, channels: c_int) {
|
||||
params_set(params.ctx, |p| p.channel_count = channels);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_set_color_primaries(params: OakVideoParams, primaries: c_int) {
|
||||
params_set(params.ctx, |p| p.color_primaries = primaries);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_set_color_transfer(params: OakVideoParams, transfer: c_int) {
|
||||
params_set(params.ctx, |p| p.color_trc = transfer);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_set_premultiplied_alpha(
|
||||
params: OakVideoParams,
|
||||
premultiplied: c_int,
|
||||
@@ -395,6 +432,7 @@ pub extern "C" fn oakcommon_videoparams_set_premultiplied_alpha(
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_videoparams_set_enabled(params: OakVideoParams, enabled: c_int) {
|
||||
params_set(params.ctx, |p| p.enabled = enabled);
|
||||
}
|
||||
@@ -607,11 +645,13 @@ pub extern "C" fn oakcore_rational_free(rational: *mut c_void) {
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_subtitleparams_get_stream_index(_params: OakSubtitleParams) -> c_int {
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_subtitleparams_generate_ass_header(
|
||||
_params: OakSubtitleParams,
|
||||
_width: c_int,
|
||||
@@ -620,6 +660,7 @@ pub extern "C" fn oakcommon_subtitleparams_generate_ass_header(
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_subtitleparams_add_subtitle(
|
||||
_params: OakSubtitleParams,
|
||||
_text: *const c_char,
|
||||
@@ -631,6 +672,7 @@ pub extern "C" fn oakcommon_subtitleparams_add_subtitle(
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_config_get_int(
|
||||
_group: *const c_char,
|
||||
_key: *const c_char,
|
||||
@@ -640,6 +682,7 @@ pub extern "C" fn oakcommon_config_get_int(
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_config_get_bool(
|
||||
_group: *const c_char,
|
||||
_key: *const c_char,
|
||||
@@ -649,6 +692,7 @@ pub extern "C" fn oakcommon_config_get_bool(
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_config_get(
|
||||
_group: *const c_char,
|
||||
_key: *const c_char,
|
||||
@@ -672,9 +716,11 @@ pub extern "C" fn oakcommon_config_get(
|
||||
static FAKE_PATH: &[u8] = b"/mock/config/oak\0";
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_filefunctions_init() {}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_filefunctions_get_configuration_location(
|
||||
buf: *mut c_char,
|
||||
buf_size: c_int,
|
||||
@@ -683,6 +729,7 @@ pub extern "C" fn oakcommon_filefunctions_get_configuration_location(
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_filefunctions_get_unique_file_identifier(path: *const c_char) -> i64 {
|
||||
if path.is_null() {
|
||||
return 0;
|
||||
@@ -695,6 +742,7 @@ pub extern "C" fn oakcommon_filefunctions_get_unique_file_identifier(path: *cons
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_filefunctions_get_application_path(
|
||||
buf: *mut c_char,
|
||||
buf_size: c_int,
|
||||
@@ -703,6 +751,7 @@ pub extern "C" fn oakcommon_filefunctions_get_application_path(
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_filefunctions_free(_ptr: *mut c_void) {}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -710,6 +759,7 @@ pub extern "C" fn oakcommon_filefunctions_free(_ptr: *mut c_void) {}
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_colortransform_init_output(
|
||||
_src_colorspace: c_int,
|
||||
_src_trc: c_int,
|
||||
@@ -722,6 +772,7 @@ pub extern "C" fn oakcommon_colortransform_init_output(
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_colortransform_get_output(params: OakVideoParams, out: *mut OakVideoParams) {
|
||||
if !out.is_null() {
|
||||
unsafe { *out = params.clone() };
|
||||
@@ -729,6 +780,7 @@ pub extern "C" fn oakcommon_colortransform_get_output(params: OakVideoParams, ou
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_colortransform_free(params: *mut OakVideoParams) {
|
||||
oakcommon_videoparams_free(params);
|
||||
}
|
||||
@@ -738,31 +790,37 @@ pub extern "C" fn oakcommon_colortransform_free(params: *mut OakVideoParams) {
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_ffmpegutils_get_native_sample_format(sample_format: c_int) -> c_int {
|
||||
sample_format
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_ffmpegutils_get_compatible_pixel_format(format: c_int) -> c_int {
|
||||
format
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_ffmpegutils_get_ffmpeg_pixel_format(format: c_int) -> c_int {
|
||||
format
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_ffmpegutils_get_ffmpeg_sample_format(format: c_int) -> c_int {
|
||||
format
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_ffmpegutils_get_compatible_bridge_pixel_format(format: c_int) -> c_int {
|
||||
format
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_ffmpegutils_convert_jpeg_space_to_regular_space(format: c_int) -> c_int {
|
||||
format
|
||||
}
|
||||
@@ -772,19 +830,23 @@ pub extern "C" fn oakcommon_ffmpegutils_convert_jpeg_space_to_regular_space(form
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_oiioutils_init() {}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_oiioutils_get_oiio_base_type_from_format(format: c_int) -> c_int {
|
||||
format
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_oiioutils_get_format_from_oiio_basetype(basetype: c_int) -> c_int {
|
||||
basetype
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_oiioutils_get_pixel_aspect_ratio(
|
||||
_width: c_int,
|
||||
_height: c_int,
|
||||
@@ -801,6 +863,7 @@ pub extern "C" fn oakcommon_oiioutils_get_pixel_aspect_ratio(
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[cfg(test)]
|
||||
pub extern "C" fn oakcommon_oiioutils_free() {}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -184,12 +184,14 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn create_destroy_instance_ok() {
|
||||
let _g = crate::ffi::lock_tests();
|
||||
assert_eq!(unsafe { oakcodec_conform_create_instance() }, crate::error::OAKCODEC_OK);
|
||||
assert_eq!(unsafe { oakcodec_conform_destroy_instance() }, crate::error::OAKCODEC_OK);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_state_maps_states() {
|
||||
let _g = crate::ffi::lock_tests();
|
||||
let _g = REG_LOCK.lock().unwrap();
|
||||
// No registrar and no files -> UNAVAILABLE.
|
||||
let cache = cstr(&temp_cache("state"));
|
||||
@@ -218,6 +220,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn filename_count_and_at() {
|
||||
let _g = crate::ffi::lock_tests();
|
||||
let cache = cstr(&temp_cache("names"));
|
||||
let src = cstr("media.mp4");
|
||||
|
||||
|
||||
@@ -350,6 +350,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn format_metadata_exports() {
|
||||
let _g = crate::ffi::lock_tests();
|
||||
let mut buf = [0i8; 64];
|
||||
|
||||
// Count matches the 15-entry table (0..=14, Count = 15).
|
||||
@@ -385,6 +386,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn format_codec_lists_exports() {
|
||||
let _g = crate::ffi::lock_tests();
|
||||
// MPEG-4 video (2) carries H.264/H.264RGB/H.265.
|
||||
assert_eq!(unsafe { oakcodec_encoding_format_video_codec_count(2) }, 3);
|
||||
assert_eq!(
|
||||
@@ -431,6 +433,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn codec_metadata_exports() {
|
||||
let _g = crate::ffi::lock_tests();
|
||||
let mut buf = [0i8; 64];
|
||||
|
||||
let rc = unsafe { oakcodec_encoding_codec_name(1, buf.as_mut_ptr(), 64) };
|
||||
@@ -451,6 +454,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn pixel_and_sample_format_exports() {
|
||||
let _g = crate::ffi::lock_tests();
|
||||
let mut buf = [0i8; 64];
|
||||
|
||||
// Bad arguments -> E_INVALID.
|
||||
@@ -497,6 +501,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn filename_helper_exports() {
|
||||
let _g = crate::ffi::lock_tests();
|
||||
let mut buf = [0i8; 128];
|
||||
|
||||
assert_eq!(
|
||||
|
||||
@@ -306,6 +306,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn create_destroy_and_params_default() {
|
||||
let _g = crate::ffi::lock_tests();
|
||||
assert_eq!(unsafe { oakcodec_proxy_create_instance() }, crate::error::OAKCODEC_OK);
|
||||
assert_eq!(unsafe { oakcodec_proxy_destroy_instance() }, crate::error::OAKCODEC_OK);
|
||||
|
||||
@@ -325,6 +326,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn get_state_and_state_to_string() {
|
||||
let _g = crate::ffi::lock_tests();
|
||||
let cache = temp_cache("state");
|
||||
let p = defaults();
|
||||
let src = cstr("media.mp4");
|
||||
@@ -358,6 +360,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn directory_working_and_get_or_start() {
|
||||
let _g = crate::ffi::lock_tests();
|
||||
let cache = temp_cache("getorstart");
|
||||
let cache_c = cstr(&cache);
|
||||
let src = cstr("media.mp4");
|
||||
@@ -416,6 +419,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn find_ffmpeg_uses_configured_path() {
|
||||
let _g = crate::ffi::lock_tests();
|
||||
// The current test binary is a real executable: the configured
|
||||
// path resolves to an absolute path.
|
||||
let me = std::env::current_exe().unwrap();
|
||||
|
||||
@@ -56,6 +56,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn register_query_clear() {
|
||||
let _g = crate::ffi::lock_tests();
|
||||
let _g = REG_LOCK.lock().unwrap();
|
||||
|
||||
assert_eq!(unsafe { oakcodec_task_submit_is_registered() }, 0);
|
||||
|
||||
Generated
+3
@@ -757,6 +757,8 @@ dependencies = [
|
||||
name = "oakaudio"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"oakcodec",
|
||||
"oakcommon",
|
||||
"oakcore-rs",
|
||||
]
|
||||
|
||||
@@ -806,6 +808,7 @@ dependencies = [
|
||||
name = "oaknode"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"oakcodec",
|
||||
"oakcommon",
|
||||
"oakcore-rs",
|
||||
"oakundo",
|
||||
|
||||
Generated
+216
-1
@@ -8,12 +8,45 @@ version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.72.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"itertools",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"shlex 1.3.0",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.25.2"
|
||||
@@ -33,7 +66,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d262e149917187838d5b42777c8253bcb64500067342904e7d429499a6f277e"
|
||||
dependencies = [
|
||||
"find-msvc-tools",
|
||||
"shlex",
|
||||
"shlex 2.0.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cexpr"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -42,6 +84,17 @@ version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "clang-sys"
|
||||
version = "1.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "157a8ba7b480713b56f4c09fd13fc3e0a22a5dfab8097ba61cbc5feef950788a"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"libc",
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cmake"
|
||||
version = "0.1.58"
|
||||
@@ -66,12 +119,43 @@ version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d"
|
||||
|
||||
[[package]]
|
||||
name = "fax"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "caf1079563223d5d59d83c85886a56e586cfd5c1a26292e971a0fa266531ac5a"
|
||||
|
||||
[[package]]
|
||||
name = "ffmpeg-next"
|
||||
version = "9.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6380599799e175191eb7ffe82c97f36a2a90a36cbc54c738a903e5287d7f516a"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"ffmpeg-sys-next",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ffmpeg-sys-next"
|
||||
version = "9.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b939bf79dd5949412a4b81cfe21a07f48ea21b47fcbb5f57816c8c2de5ae30b"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"cc",
|
||||
"libc",
|
||||
"num_cpus",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.10"
|
||||
@@ -88,6 +172,12 @@ dependencies = [
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b"
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "2.7.1"
|
||||
@@ -99,6 +189,12 @@ dependencies = [
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
|
||||
|
||||
[[package]]
|
||||
name = "image"
|
||||
version = "0.25.10"
|
||||
@@ -112,6 +208,31 @@ dependencies = [
|
||||
"tiff",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.189"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.8.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.33"
|
||||
@@ -124,6 +245,12 @@ version = "2.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.9"
|
||||
@@ -144,6 +271,16 @@ dependencies = [
|
||||
"pxfm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
@@ -153,6 +290,24 @@ dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oakcodec"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"ffmpeg-next",
|
||||
"oakcore-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oakcommon"
|
||||
version = "0.1.0"
|
||||
@@ -172,6 +327,7 @@ version = "0.1.0"
|
||||
name = "oaknode"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"oakcodec",
|
||||
"oakcommon",
|
||||
"oakcore-rs",
|
||||
"oakundo",
|
||||
@@ -204,6 +360,12 @@ dependencies = [
|
||||
"cmake",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.107"
|
||||
@@ -243,6 +405,47 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d"
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "2.0.1"
|
||||
@@ -306,12 +509,24 @@ version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "weezl"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88"
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.56"
|
||||
|
||||
@@ -16,9 +16,16 @@ panic = "unwind"
|
||||
oakcore-rs = { path = "../../oakcore-rs" }
|
||||
oakcommon = { path = "../../common/rust" }
|
||||
oakundo = { path = "../../undo/rust" }
|
||||
oakcodec = { path = "../../codec/rust" }
|
||||
|
||||
[features]
|
||||
# In-crate stubs for the oakundo C ABI (and other module bridges) so
|
||||
# cargo test can exercise the undoable exports end-to-end without the
|
||||
# module libraries; real builds (feature off) dlsym the actual modules.
|
||||
test-stubs = []
|
||||
|
||||
[dev-dependencies]
|
||||
# oakcodec's oakcore_*/oakrender_* host-mocks (test-stubs feature): the
|
||||
# node test binaries link the real oakcodec (footage probe), whose ffmpeg
|
||||
# unit references those cross-crate symbols that no Rust crate provides.
|
||||
oakcodec = { path = "../../codec/rust", features = ["test-stubs"] }
|
||||
|
||||
@@ -14,21 +14,19 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! oakcodec C ABI imports (footage probing). dlsym-resolved (see
|
||||
//! [`super`]).
|
||||
//! oakcodec C ABI calls (footage probing) — now direct Rust calls into
|
||||
//! the oakcodec crate (single-lib unification, see
|
||||
//! `docs/zh/plans/riir/single-lib.md`).
|
||||
|
||||
use std::ffi::c_char;
|
||||
use std::ffi::c_int;
|
||||
|
||||
use crate::handle::CHandle;
|
||||
|
||||
/// `oakcodec_decoder_probe` — fills stream info for a media file.
|
||||
pub fn decoder_probe(path: &str, out: *mut CHandle) -> Option<c_int> {
|
||||
use crate::bridge::dlsym;
|
||||
/// `oakcodec_decoder_probe` — probe a media file, returning the
|
||||
/// stream-list handle (`oakcodec_decoder_probe(filename)`). The caller
|
||||
/// owns the returned handle.
|
||||
pub fn decoder_probe(path: &str) -> Option<CHandle> {
|
||||
use std::ffi::CString;
|
||||
type F = unsafe extern "C" fn(*const c_char, *mut CHandle) -> c_int;
|
||||
let c = CString::new(path).ok()?;
|
||||
dlsym::call::<F, c_int>("oakcodec_decoder_probe", |f| unsafe {
|
||||
f(c.as_ptr(), out)
|
||||
})
|
||||
Some(unsafe { oakcodec::ffi::decoder::oakcodec_decoder_probe(c.as_ptr()) })
|
||||
}
|
||||
|
||||
+115
-1415
File diff suppressed because it is too large
Load Diff
@@ -89,33 +89,27 @@ impl FootageBehavior {
|
||||
/// preserved on failure (no partial state).
|
||||
pub fn probe(&mut self) -> crate::error::Result<()> {
|
||||
use crate::error::Error;
|
||||
let mut out = crate::handle::CHandle::null();
|
||||
let rc = match crate::bridge::codec::decoder_probe(&self.filename, &mut out) {
|
||||
Some(rc) => rc,
|
||||
// Direct call into the oakcodec crate (single-lib unification):
|
||||
// `oakcodec_decoder_probe(filename)` returns the stream-list
|
||||
// handle (owned by the caller).
|
||||
let out = match crate::bridge::codec::decoder_probe(&self.filename) {
|
||||
Some(out) => out,
|
||||
None => {
|
||||
return Err(Error::Failed(
|
||||
"oakcodec unavailable (not linked)".to_string(),
|
||||
));
|
||||
}
|
||||
};
|
||||
if rc != 0 {
|
||||
return Err(Error::Failed(format!(
|
||||
"oakcodec probe failed with code {}",
|
||||
rc
|
||||
)));
|
||||
}
|
||||
if out.ctx.is_null() {
|
||||
if out.is_null() {
|
||||
return Err(Error::Failed(
|
||||
"oakcodec probe returned no streams".to_string(),
|
||||
));
|
||||
}
|
||||
// The probe result handle is an oakcodec stream-list; without a
|
||||
// codec module in tests it never gets here (symbol absent). The
|
||||
// real bridge populates `streams` through the codec C ABI.
|
||||
// The probe result handle is an oakcodec stream-list. Reading
|
||||
// stream entries into `streams` is a Phase-2 follow-up (the
|
||||
// exact accessor symbols are pinned when the codec module C ABI
|
||||
// is finalized).
|
||||
let _ = out;
|
||||
// TODO(bridge::codec): read stream entries from the handle and
|
||||
// fill `streams`; the exact accessor symbols are pinned when the
|
||||
// codec module C ABI is finalized (Phase 2 follow-up).
|
||||
self.valid = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -170,8 +170,14 @@ static RENDER: std::sync::Mutex<Option<TextRenderBackend>> = std::sync::Mutex::n
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
// The two tests below share the process-global backend statics; a
|
||||
// lock serializes them so `backend_hooks_default_none` cannot observe
|
||||
// the hooks installed by `backend_hooks_install_and_query`.
|
||||
static LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
|
||||
|
||||
#[test]
|
||||
fn backend_hooks_default_none() {
|
||||
let _guard = LOCK.lock().unwrap();
|
||||
set_text_backends(None, None);
|
||||
assert_eq!(text_measure_backend(), None);
|
||||
assert_eq!(text_render_backend(), None);
|
||||
@@ -179,6 +185,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn backend_hooks_install_and_query() {
|
||||
let _guard = LOCK.lock().unwrap();
|
||||
fn measure(_r: &TextLayoutRequest) -> TextLayoutSize {
|
||||
TextLayoutSize {
|
||||
width: 12.0,
|
||||
|
||||
@@ -1,217 +0,0 @@
|
||||
// Oak Video Editor - Non-Linear Video Editor
|
||||
// Copyright (C) 2026 Oak Team
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! oakcodec C ABI imports (frame payloads for texture upload, disk-cache
|
||||
//! frame read/write).
|
||||
//!
|
||||
//! Written against the frozen `include/codec/*.h` contract and resolved
|
||||
//! through [`crate::bridge::dlsym`]. The oakcodec crate is being finished
|
||||
//! concurrently; until it lands, the missing symbols fail explainably and
|
||||
//! the codec-dependent tests are `#[ignore = "needs oakcodec final"]`.
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
use crate::frame::VideoParamsPod;
|
||||
use crate::handle::CHandle;
|
||||
use crate::texture::Frame;
|
||||
|
||||
/// An `OakFrame` handle (include/codec/frame.h).
|
||||
pub type CodecFrameHandle = CHandle;
|
||||
|
||||
/// Whether the oakcodec C ABI is present in the process.
|
||||
pub fn codec_abi_available() -> bool {
|
||||
crate::bridge::dlsym::resolve("oakcodec_frame_free").is_some()
|
||||
}
|
||||
|
||||
/// Release a codec frame handle (`oakcodec_frame_free`).
|
||||
///
|
||||
/// # Safety
|
||||
/// `frame` must be a handle obtained from the codec module.
|
||||
pub unsafe fn frame_free(frame: *mut CodecFrameHandle) {
|
||||
type F = unsafe extern "C" fn(*mut CodecFrameHandle);
|
||||
let _ = crate::bridge::dlsym::call::<F, ()>("oakcodec_frame_free", |f| unsafe { f(frame) });
|
||||
}
|
||||
|
||||
/// Marshal an `OakFrame` handle into a CPU [`Frame`]
|
||||
/// (`oakcodec_frame_get_params` / `_data` / `_linesize_bytes` /
|
||||
/// `_get_timestamp`).
|
||||
///
|
||||
/// Fails with `Error::Failed` when the codec C ABI is absent, or with
|
||||
/// `Error::Invalid` for a null frame handle.
|
||||
///
|
||||
/// # Safety
|
||||
/// `frame` must be a valid `OakFrame` handle.
|
||||
pub unsafe fn frame_to_cpu(frame: CodecFrameHandle) -> Result<Frame> {
|
||||
if frame.is_null() {
|
||||
return Err(Error::Invalid);
|
||||
}
|
||||
if !codec_abi_available() {
|
||||
return Err(Error::Failed(
|
||||
"oakcodec C ABI not present (oakcodec crate pending)".into(),
|
||||
));
|
||||
}
|
||||
let mut pod = oakcommon_video_params_zeroed();
|
||||
type GetParamsF = unsafe extern "C" fn(CodecFrameHandle, *mut OakVideoParamsPod) -> i32;
|
||||
let rc = crate::bridge::dlsym::call::<GetParamsF, i32>("oakcodec_frame_get_params", |f| unsafe {
|
||||
f(frame, &mut pod)
|
||||
})
|
||||
.ok_or_else(|| Error::Failed("oakcodec_frame_get_params missing".into()))?;
|
||||
if rc != 0 {
|
||||
return Err(Error::Failed(format!("oakcodec_frame_get_params rc={rc}")));
|
||||
}
|
||||
|
||||
type WidthF = unsafe extern "C" fn(CodecFrameHandle) -> i32;
|
||||
let width = crate::bridge::dlsym::call::<WidthF, i32>("oakcodec_frame_width", |f| unsafe {
|
||||
f(frame)
|
||||
})
|
||||
.unwrap_or(0);
|
||||
let height = crate::bridge::dlsym::call::<WidthF, i32>("oakcodec_frame_height", |f| unsafe {
|
||||
f(frame)
|
||||
})
|
||||
.unwrap_or(0);
|
||||
let format = crate::bridge::dlsym::call::<WidthF, i32>("oakcodec_frame_format", |f| unsafe {
|
||||
f(frame)
|
||||
})
|
||||
.unwrap_or(-1);
|
||||
let channels =
|
||||
crate::bridge::dlsym::call::<WidthF, i32>("oakcodec_frame_channel_count", |f| unsafe {
|
||||
f(frame)
|
||||
})
|
||||
.unwrap_or(0);
|
||||
let linesize =
|
||||
crate::bridge::dlsym::call::<WidthF, i32>("oakcodec_frame_linesize_bytes", |f| unsafe {
|
||||
f(frame)
|
||||
})
|
||||
.unwrap_or(0);
|
||||
let data = crate::bridge::dlsym::call::<DataF, *mut u8>("oakcodec_frame_data", |f| unsafe {
|
||||
f(frame)
|
||||
})
|
||||
.unwrap_or(std::ptr::null_mut());
|
||||
if data.is_null() || linesize <= 0 || width <= 0 || height <= 0 {
|
||||
return Err(Error::Failed("frame not allocated".into()));
|
||||
}
|
||||
|
||||
type TsF = unsafe extern "C" fn(CodecFrameHandle, *mut i32, *mut i32) -> i32;
|
||||
let (mut tn, mut td) = (0i32, 1i32);
|
||||
let _ = crate::bridge::dlsym::call::<TsF, i32>("oakcodec_frame_get_timestamp", |f| unsafe {
|
||||
f(frame, &mut tn, &mut td)
|
||||
});
|
||||
|
||||
let mut cpu = Frame::new();
|
||||
let pod = VideoParamsPod {
|
||||
width,
|
||||
height,
|
||||
time_base_num: pod.time_base_num,
|
||||
time_base_den: pod.time_base_den,
|
||||
format,
|
||||
pixel_aspect_num: pod.pixel_aspect_num,
|
||||
pixel_aspect_den: pod.pixel_aspect_den,
|
||||
interlacing: pod.interlacing,
|
||||
color_range: pod.color_range,
|
||||
divider: pod.divider,
|
||||
video_type: pod.video_type,
|
||||
premultiplied_alpha: pod.premultiplied_alpha,
|
||||
};
|
||||
cpu.set_video_params(pod);
|
||||
cpu.channels = channels;
|
||||
cpu.timestamp = oakcore_rs::Rational::new(tn as i64, td as i64);
|
||||
let size = (linesize as usize)
|
||||
.saturating_mul(height as usize)
|
||||
.min(1usize << 31);
|
||||
cpu.data = unsafe { std::slice::from_raw_parts(data, size).to_vec() };
|
||||
Ok(cpu)
|
||||
}
|
||||
|
||||
type DataF = unsafe extern "C" fn(CodecFrameHandle) -> *mut u8;
|
||||
|
||||
/// Mirror of the `OakVideoParams` POD (include/common/videoparams.h) used
|
||||
/// by `oakcodec_frame_get_params`.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
struct OakVideoParamsPod {
|
||||
width: i32,
|
||||
height: i32,
|
||||
time_base_num: i32,
|
||||
time_base_den: i32,
|
||||
format: i32,
|
||||
pixel_aspect_num: i32,
|
||||
pixel_aspect_den: i32,
|
||||
interlacing: i32,
|
||||
color_range: i32,
|
||||
divider: i32,
|
||||
video_type: i32,
|
||||
premultiplied_alpha: i32,
|
||||
}
|
||||
|
||||
fn oakcommon_video_params_zeroed() -> OakVideoParamsPod {
|
||||
// Safe: POD of ints.
|
||||
unsafe { std::mem::zeroed() }
|
||||
}
|
||||
|
||||
/// Frame-payload write for the disk frame cache. Fails with
|
||||
/// `Error::Failed` when the codec C ABI is absent.
|
||||
///
|
||||
/// # Safety
|
||||
/// `frame` must be a valid `OakFrame` handle with an allocated buffer.
|
||||
pub unsafe fn frame_write_disk(frame: CodecFrameHandle, path: &str) -> Result<()> {
|
||||
if !codec_abi_available() {
|
||||
return Err(Error::Failed(
|
||||
"oakcodec C ABI not present (oakcodec crate pending)".into(),
|
||||
));
|
||||
}
|
||||
// The codec crate owns the EXR/JPEG disk format. The symbol name is
|
||||
// part of the codec contract; wrapped defensively.
|
||||
#[repr(C)]
|
||||
struct FsArg {
|
||||
codec_frame: CodecFrameHandle,
|
||||
path: *const std::ffi::c_char,
|
||||
}
|
||||
let path_c = std::ffi::CString::new(path)
|
||||
.map_err(|_| Error::Invalid)?;
|
||||
let arg = FsArg {
|
||||
codec_frame: frame,
|
||||
path: path_c.as_ptr(),
|
||||
};
|
||||
type F = unsafe extern "C" fn(*const FsArg) -> i32;
|
||||
let rc = crate::bridge::dlsym::call::<F, i32>("oakcodec_frame_write_file", |f| unsafe {
|
||||
f(&arg)
|
||||
})
|
||||
.ok_or_else(|| Error::Failed("oakcodec_frame_write_file missing".into()))?;
|
||||
if rc == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::Failed(format!("oakcodec_frame_write_file rc={rc}")))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn missing_codec_abi_fails_explainably() {
|
||||
let rc = unsafe { frame_to_cpu(CHandle::null()) };
|
||||
assert!(rc.is_err(), "null frame rejected");
|
||||
let rc = unsafe { frame_to_cpu(CHandle {
|
||||
ctx: 1 as *mut std::ffi::c_void,
|
||||
addref: None,
|
||||
release: None,
|
||||
abi_version: 1,
|
||||
}) };
|
||||
if !codec_abi_available() {
|
||||
assert!(rc.is_err());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,12 +14,10 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! oakcommon C ABI imports (config, file functions, strings).
|
||||
//!
|
||||
//! Symbols resolve through [`crate::bridge::dlsym`]; a missing symbol
|
||||
//! yields the documented fallback (config defaults, the mirrored
|
||||
//! configuration-location computation) so the crate stays testable and
|
||||
//! linkable without liboakcommon.
|
||||
//! oakcommon C ABI calls (config, file functions, strings) — now direct
|
||||
//! Rust calls into the oakcommon crate (single-lib unification, see
|
||||
//! `docs/zh/plans/riir/single-lib.md`). The configuration-location and
|
||||
//! disk-cache helpers delegate to oakcommon's own implementation.
|
||||
|
||||
use std::ffi::{c_char, c_int};
|
||||
use std::sync::Mutex;
|
||||
@@ -30,26 +28,27 @@ use std::sync::Mutex;
|
||||
pub fn config_get_string(group: Option<&str>, key: &str) -> Option<String> {
|
||||
let group_c = group.and_then(|g| std::ffi::CString::new(g).ok());
|
||||
let key_c = std::ffi::CString::new(key).ok()?;
|
||||
type F = unsafe extern "C" fn(*const c_char, *const c_char, *mut c_char, c_int) -> c_int;
|
||||
crate::bridge::dlsym::call::<F, i32>("oakcommon_config_get", |f| unsafe {
|
||||
let group_ptr = group_c.as_ref().map_or(std::ptr::null(), |c| c.as_ptr());
|
||||
f(group_ptr, key_c.as_ptr(), std::ptr::null_mut(), 0)
|
||||
})
|
||||
.and_then(|size| {
|
||||
if size <= 1 {
|
||||
return None; // missing or empty
|
||||
}
|
||||
let mut buf = vec![0u8; size as usize];
|
||||
let group_ptr = group_c.as_ref().map_or(std::ptr::null(), |c| c.as_ptr());
|
||||
let got = crate::bridge::dlsym::call::<F, i32>("oakcommon_config_get", |f| unsafe {
|
||||
f(group_ptr, key_c.as_ptr(), buf.as_mut_ptr() as *mut c_char, size)
|
||||
})?;
|
||||
if got <= 0 {
|
||||
return None;
|
||||
}
|
||||
let end = buf.iter().position(|&b| b == 0).unwrap_or(buf.len());
|
||||
Some(String::from_utf8_lossy(&buf[..end]).into_owned())
|
||||
})
|
||||
let group_ptr = || group_c.as_ref().map_or(std::ptr::null(), |c| c.as_ptr());
|
||||
let size = unsafe {
|
||||
oakcommon::ffi::config::oakcommon_config_get(group_ptr(), key_c.as_ptr(), std::ptr::null_mut(), 0)
|
||||
};
|
||||
if size <= 1 {
|
||||
return None; // missing or empty
|
||||
}
|
||||
let mut buf = vec![0u8; size as usize];
|
||||
let got = unsafe {
|
||||
oakcommon::ffi::config::oakcommon_config_get(
|
||||
group_ptr(),
|
||||
key_c.as_ptr(),
|
||||
buf.as_mut_ptr() as *mut c_char,
|
||||
size,
|
||||
)
|
||||
};
|
||||
if got <= 0 {
|
||||
return None;
|
||||
}
|
||||
let end = buf.iter().position(|&b| b == 0).unwrap_or(buf.len());
|
||||
Some(String::from_utf8_lossy(&buf[..end]).into_owned())
|
||||
}
|
||||
|
||||
/// `oakcommon_config_get_int(group, key, default)`.
|
||||
@@ -59,99 +58,17 @@ pub fn config_get_int(group: Option<&str>, key: &str, default: i32) -> i32 {
|
||||
Ok(c) => c,
|
||||
Err(_) => return default,
|
||||
};
|
||||
type F = unsafe extern "C" fn(*const c_char, *const c_char, c_int) -> c_int;
|
||||
crate::bridge::dlsym::call::<F, i32>("oakcommon_config_get_int", |f| unsafe {
|
||||
let group_ptr = group_c.as_ref().map_or(std::ptr::null(), |c| c.as_ptr());
|
||||
f(group_ptr, key_c.as_ptr(), default)
|
||||
})
|
||||
.unwrap_or(default)
|
||||
let group_ptr = group_c.as_ref().map_or(std::ptr::null(), |c| c.as_ptr());
|
||||
unsafe { oakcommon::ffi::config::oakcommon_config_get_int(group_ptr, key_c.as_ptr(), default) }
|
||||
}
|
||||
|
||||
/// The configuration directory.
|
||||
///
|
||||
/// Primary path: `oakcommon_filefunctions_get_configuration_location()`
|
||||
/// (two-stage, needs an `OakFileFunctions` handle obtained through
|
||||
/// `oakcommon_filefunctions_init()`). Fallback (mirror of
|
||||
/// `FileFunctions::get_configuration_location()` in common/rust/src/
|
||||
/// filefunctions.rs): `OAK_CONFIG_DIR` → portable app dir → macOS
|
||||
/// `~/Library/Application Support` (or `$XDG_CONFIG_HOME`/`~/.config` on
|
||||
/// other platforms) → temp directory. The fallback keeps `cargo test`
|
||||
/// deterministic through the `OAK_CONFIG_DIR` env var.
|
||||
/// The configuration directory — oakcommon's implementation
|
||||
/// (`FileFunctions::get_configuration_location`, honoring `OAK_CONFIG_DIR`
|
||||
/// and the platform fallbacks).
|
||||
pub fn configuration_location() -> String {
|
||||
// 1) Env override (also honored by the C++ side).
|
||||
if let Ok(dir) = std::env::var("OAK_CONFIG_DIR") {
|
||||
if !dir.is_empty() {
|
||||
let _ = std::fs::create_dir_all(&dir);
|
||||
return dir;
|
||||
}
|
||||
}
|
||||
|
||||
// 2) The real C ABI (force-loaded oakcommon in the app process).
|
||||
if let Some(path) = configuration_location_via_abi() {
|
||||
return path;
|
||||
}
|
||||
|
||||
// 3) Mirrored fallback.
|
||||
#[cfg(target_os = "macos")]
|
||||
let config_root = match std::env::var("HOME") {
|
||||
Ok(h) if !h.is_empty() => {
|
||||
std::path::PathBuf::from(h).join("Library").join("Application Support")
|
||||
}
|
||||
_ => std::path::PathBuf::new(),
|
||||
};
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
let config_root = match std::env::var("XDG_CONFIG_HOME") {
|
||||
Ok(x) if !x.is_empty() => std::path::PathBuf::from(x),
|
||||
_ => match std::env::var("HOME") {
|
||||
Ok(h) if !h.is_empty() => std::path::PathBuf::from(h).join(".config"),
|
||||
_ => std::path::PathBuf::new(),
|
||||
},
|
||||
};
|
||||
|
||||
if config_root.as_os_str().is_empty() {
|
||||
std::env::temp_dir().to_string_lossy().into_owned()
|
||||
} else {
|
||||
config_root.to_string_lossy().into_owned()
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolve the configuration location through the oakcommon C ABI
|
||||
/// (`oakcommon_filefunctions_init` + `_get_configuration_location`).
|
||||
fn configuration_location_via_abi() -> Option<String> {
|
||||
type InitF = unsafe extern "C" fn() -> crate::handle::CHandle;
|
||||
let handle =
|
||||
crate::bridge::dlsym::call::<InitF, crate::handle::CHandle>("oakcommon_filefunctions_init", |f| {
|
||||
unsafe { f() }
|
||||
})?;
|
||||
if handle.is_null() {
|
||||
return None;
|
||||
}
|
||||
type GetF = unsafe extern "C" fn(crate::handle::CHandle, *mut c_char, c_int) -> c_int;
|
||||
let size = crate::bridge::dlsym::call::<GetF, i32>(
|
||||
"oakcommon_filefunctions_get_configuration_location",
|
||||
|f| unsafe { f(handle, std::ptr::null_mut(), 0) },
|
||||
)?;
|
||||
let result = if size <= 1 {
|
||||
None
|
||||
} else {
|
||||
let mut buf = vec![0u8; size as usize];
|
||||
let got = crate::bridge::dlsym::call::<GetF, i32>(
|
||||
"oakcommon_filefunctions_get_configuration_location",
|
||||
|f| unsafe { f(handle, buf.as_mut_ptr() as *mut c_char, size) },
|
||||
)?;
|
||||
if got <= 0 {
|
||||
None
|
||||
} else {
|
||||
let end = buf.iter().position(|&b| b == 0).unwrap_or(buf.len());
|
||||
Some(String::from_utf8_lossy(&buf[..end]).into_owned())
|
||||
}
|
||||
};
|
||||
type FreeF = unsafe extern "C" fn(*mut crate::handle::CHandle);
|
||||
let mut h = handle;
|
||||
let _ = crate::bridge::dlsym::call::<FreeF, ()>("oakcommon_filefunctions_free", |f| unsafe {
|
||||
f(&mut h)
|
||||
});
|
||||
result
|
||||
oakcommon::filefunctions::FileFunctions::new()
|
||||
.get_configuration_location()
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Serializes tests that mutate `OAK_CONFIG_DIR` / `OAK_RENDER_BACKEND`
|
||||
@@ -161,10 +78,7 @@ pub static ENV_TEST_LOCK: Mutex<()> = Mutex::new(());
|
||||
/// The default disk cache directory (C++ `DiskManager::
|
||||
/// get_default_disk_cache_path`): `<configuration_location>/mediacache`.
|
||||
pub fn default_disk_cache_path() -> String {
|
||||
std::path::Path::new(&configuration_location())
|
||||
.join("mediacache")
|
||||
.to_string_lossy()
|
||||
.into_owned()
|
||||
oakcommon::filefunctions::default_disk_cache_path()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -172,8 +86,8 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn config_missing_symbol_falls_back() {
|
||||
// No liboakcommon in cargo test: defaults apply.
|
||||
fn config_missing_key_falls_back() {
|
||||
// The real config store is empty under cargo test: defaults apply.
|
||||
assert_eq!(config_get_int(None, "GraphicsBackend", 7), 7);
|
||||
assert_eq!(config_get_string(None, "missing"), None);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
//! the wrapper returns a documented fallback (empty handle / negative
|
||||
//! error code) instead of a link error.
|
||||
|
||||
pub mod codec;
|
||||
pub mod common;
|
||||
pub mod node;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user