From 2b38afb3464b86d65d354a0aef1f4a71658e92dc Mon Sep 17 00:00:00 2001 From: eater <=@eater.me> Date: Mon, 13 Sep 2021 12:20:29 +0200 Subject: [PATCH] undefined progress --- Cargo.lock | 1458 +++++++++++++++++++++++-------------- Cargo.toml | 26 +- resources/favicon.ico | Bin 0 -> 67646 bytes resources/player.html | 67 ++ src/av/format.rs | 34 +- src/av/mod.rs | 19 +- src/av/stream.rs | 22 +- src/av/xcoder.rs | 34 +- src/main.rs | 206 +++++- src/transcoder.rs | 492 ++++++++++--- src/transcoder_manager.rs | 413 +++++++++-- src/utils/mod.rs | 6 + templates/manifest.xml | 34 + test/index.html | 66 -- 14 files changed, 2061 insertions(+), 816 deletions(-) create mode 100644 resources/favicon.ico create mode 100644 resources/player.html create mode 100644 templates/manifest.xml diff --git a/Cargo.lock b/Cargo.lock index 72e732c..fed3590 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,115 +1,194 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -[[package]] -name = "addr2line" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b6a2d3371669ab3ca9797670853d61402b03d0b4b9ebf33d677dfa720203072" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" +version = 3 [[package]] name = "aead" -version = "0.2.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cf01b9b56e767bb57b94ebf91a58b338002963785cdd7013e21c0d4679471e4" +checksum = "7fc95d1bdb8e6666b2b217308eeeb09f2d6728d104be3e31916cc74d15420331" dependencies = [ "generic-array", ] [[package]] name = "aes" -version = "0.3.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54eb1d8fe354e5fc611daf4f2ea97dd45a765f4f1e4512306ec183ae2e8f20c9" +checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561" dependencies = [ "aes-soft", "aesni", - "block-cipher-trait", + "cipher", ] [[package]] name = "aes-gcm" -version = "0.5.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "834a6bda386024dbb7c8fc51322856c10ffe69559f972261c868485f5759c638" +checksum = "5278b5fabbb9bd46e24aa69b2fdea62c99088e0a950a9be40e3e0101298f88da" dependencies = [ "aead", "aes", - "block-cipher-trait", + "cipher", + "ctr", "ghash", - "subtle 2.2.3", - "zeroize", + "subtle", ] [[package]] name = "aes-soft" -version = "0.3.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfd7e7ae3f9a1fb5c03b389fc6bb9a51400d0c13053f0dca698c832bfd893a0d" +checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" dependencies = [ - "block-cipher-trait", - "byteorder", + "cipher", "opaque-debug", ] [[package]] name = "aesni" -version = "0.6.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f70a6b5f971e473091ab7cfb5ffac6cde81666c4556751d8d5620ead8abf100" +checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" dependencies = [ - "block-cipher-trait", + "cipher", "opaque-debug", ] [[package]] -name = "aho-corasick" -version = "0.7.10" +name = "anyhow" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1" + +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "askama" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" +checksum = "d298738b6e47e1034e560e5afe63aa488fea34e25ec11b855a76f0d7b8e73134" dependencies = [ - "memchr", + "askama_derive", + "askama_escape", + "askama_shared", ] [[package]] -name = "ansi_term" -version = "0.11.0" +name = "askama_derive" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +checksum = "ca2925c4c290382f9d2fa3d1c1b6a63fa1427099721ecca4749b154cc9c25522" dependencies = [ - "winapi", + "askama_shared", + "proc-macro2", + "syn", ] [[package]] -name = "anyhow" -version = "1.0.31" +name = "askama_escape" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90c108c1a94380c89d2215d0ac54ce09796823cca0fd91b299cfff3b33e346fb" + +[[package]] +name = "askama_shared" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85bb70cc08ec97ca5450e6eba421deeea5f172c0fc61f78b5357b2a8e8be195f" +checksum = "2582b77e0f3c506ec4838a25fa8a5f97b9bed72bb6d3d272ea1c031d8bd373bc" +dependencies = [ + "askama_escape", + "humansize", + "nom 6.1.2", + "num-traits", + "percent-encoding", + "proc-macro2", + "quote", + "serde", + "syn", + "toml", +] [[package]] name = "async-attributes" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd3d156917d94862e779f356c5acae312b08fd3121e792c857d7928c8088423" +checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" dependencies = [ "quote", "syn", ] +[[package]] +name = "async-channel" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-dup" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7427a12b8dc09291528cfb1da2447059adb4a257388c2acd6497a79d55cf6f7c" +dependencies = [ + "futures-io", + "simple-mutex", +] + +[[package]] +name = "async-executor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "once_cell", + "slab", +] + +[[package]] +name = "async-global-executor" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9586ec52317f36de58453159d48351bc244bc24ced3effc1fce22f3d48664af6" +dependencies = [ + "async-channel", + "async-executor", + "async-io", + "async-mutex", + "blocking", + "futures-lite", + "num_cpus", + "once_cell", +] + [[package]] name = "async-h1" -version = "2.1.0" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ad1494db96c4a94ca8a31a9aa56f15f3419c98bd4d3575f1ba682a06f5c1ac7" +checksum = "cc5142de15b549749cce62923a50714b0d7b77f5090ced141599e78899865451" dependencies = [ + "async-channel", + "async-dup", "async-std", "byte-pool", "futures-core", @@ -117,89 +196,161 @@ dependencies = [ "httparse", "lazy_static", "log", - "pin-project-lite", + "pin-project", +] + +[[package]] +name = "async-io" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a811e6a479f2439f0c04038796b5cfb3d2ad56c230e0f2d3f7b04d68cfee607b" +dependencies = [ + "concurrent-queue", + "futures-lite", + "libc", + "log", + "once_cell", + "parking", + "polling", + "slab", + "socket2", + "waker-fn", + "winapi", +] + +[[package]] +name = "async-lock" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6a8ea61bf9947a1007c5cada31e647dbc77b103c679858150003ba697ea798b" +dependencies = [ + "event-listener", +] + +[[package]] +name = "async-mutex" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e" +dependencies = [ + "event-listener", +] + +[[package]] +name = "async-process" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b21b63ab5a0db0369deb913540af2892750e42d949faacc7a61495ac418a1692" +dependencies = [ + "async-io", + "blocking", + "cfg-if 1.0.0", + "event-listener", + "futures-lite", + "libc", + "once_cell", + "signal-hook", + "winapi", +] + +[[package]] +name = "async-session" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "345022a2eed092cd105cc1b26fd61c341e100bd5fcbbd792df4baf31c2cc631f" +dependencies = [ + "anyhow", + "async-std", + "async-trait", + "base64 0.12.3", + "bincode", + "blake3", + "chrono", + "hmac 0.8.1", + "kv-log-macro", + "rand 0.7.3", + "serde", + "serde_json", + "sha2", ] [[package]] name = "async-sse" -version = "3.0.0" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aff0a3074c2c3cfd76417f6e03d5c99822d3ef37387af891e4a8bf46447ca870" +checksum = "53bba003996b8fd22245cd0c59b869ba764188ed435392cf2796d03b805ade10" dependencies = [ + "async-channel", "async-std", "http-types", "log", "memchr", - "pin-project-lite", + "pin-project-lite 0.1.12", ] [[package]] name = "async-std" -version = "1.6.2" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00d68a33ebc8b57800847d00787307f84a562224a14db069b0acefe4c2abbf5d" +checksum = "f8056f1455169ab86dd47b47391e4ab0cbd25410a70e9fe675544f49bafaf952" dependencies = [ "async-attributes", - "async-task", + "async-channel", + "async-global-executor", + "async-io", + "async-lock", + "async-process", "crossbeam-utils", "futures-channel", "futures-core", "futures-io", - "futures-timer", + "futures-lite", + "gloo-timers", "kv-log-macro", "log", "memchr", "num_cpus", "once_cell", - "pin-project-lite", + "pin-project-lite 0.2.7", "pin-utils", "slab", - "smol", "wasm-bindgen-futures", ] [[package]] name = "async-task" -version = "3.0.0" +version = "4.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17772156ef2829aadc587461c7753af20b7e8db1529bc66855add962a3b35d3" +checksum = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0" [[package]] -name = "atty" -version = "0.2.14" +name = "async-trait" +version = "0.1.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e" dependencies = [ - "hermit-abi", - "libc", - "winapi", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "autocfg" +name = "atomic-waker" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" +checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" [[package]] -name = "backtrace" -version = "0.3.50" +name = "autocfg" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46254cf2fdcdf1badb5934448c1bcbe046a56537b3987d96c51a7afc5d03f293" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "base-x" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b20b618342cf9891c292c4f5ac2cde7287cc5c87e87e9c769d617793607dec1" +checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" [[package]] name = "base64" @@ -207,6 +358,21 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + [[package]] name = "bindgen" version = "0.54.0" @@ -215,98 +381,95 @@ checksum = "66c0bb6167449588ff70803f4127f0684f9063097eca5016f37eb52b92c2cf36" dependencies = [ "bitflags", "cexpr", - "cfg-if", + "cfg-if 0.1.10", "clang-sys", - "clap", - "env_logger", "lazy_static", "lazycell", - "log", "peeking_take_while", "proc-macro2", "quote", "regex", "rustc-hash", "shlex", - "which", ] [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] -name = "block-buffer" -version = "0.7.3" +name = "bitvec" +version = "0.19.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +checksum = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321" dependencies = [ - "block-padding", - "byte-tools", - "byteorder", - "generic-array", + "funty", + "radium", + "tap", + "wyz", ] [[package]] -name = "block-cipher-trait" -version = "0.6.2" +name = "blake3" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c924d49bd09e7c06003acda26cd9742e796e34282ec6c1189404dee0c1f4774" +checksum = "b64485778c4f16a6a5a9d335e80d449ac6c70cdd6a06d2af18a6f6f775a125b3" dependencies = [ - "generic-array", + "arrayref", + "arrayvec", + "cc", + "cfg-if 0.1.10", + "constant_time_eq", + "crypto-mac 0.8.0", + "digest", ] [[package]] -name = "block-padding" -version = "0.1.5" +name = "block-buffer" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "byte-tools", + "generic-array", ] [[package]] name = "blocking" -version = "0.4.6" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d17efb70ce4421e351d61aafd90c16a20fb5bfe339fcdc32a86816280e62ce0" +checksum = "c5e170dbede1f740736619b776d7251cb1b9095c435c34d8ca9f57fcd2f335e9" dependencies = [ - "futures-channel", - "futures-util", + "async-channel", + "async-task", + "atomic-waker", + "fastrand", + "futures-lite", "once_cell", - "parking", - "waker-fn", ] [[package]] name = "bumpalo" -version = "3.4.0" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" +checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631" [[package]] name = "byte-pool" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9342e102eac8b1879fbedf9a7e0572c40b0cc5805b663c4d4ca791cae0bae221" +checksum = "f8c7230ddbb427b1094d477d821a99f3f54d36333178eeb806e279bcdcecf0ca" dependencies = [ "crossbeam-queue", "stable_deref_trait", ] -[[package]] -name = "byte-tools" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" - [[package]] name = "byteorder" -version = "1.3.4" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cache-padded" @@ -316,9 +479,9 @@ checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba" [[package]] name = "cc" -version = "1.0.54" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bbb73db36c1246e9034e307d0fba23f9a2e251faa47ade70c1bd252220c8311" +checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0" [[package]] name = "cexpr" @@ -326,7 +489,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27" dependencies = [ - "nom", + "nom 5.1.2", ] [[package]] @@ -335,6 +498,35 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "serde", + "time 0.1.43", + "winapi", +] + +[[package]] +name = "cipher" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" +dependencies = [ + "generic-array", +] + [[package]] name = "clang-sys" version = "0.29.3" @@ -347,179 +539,223 @@ dependencies = [ ] [[package]] -name = "clap" -version = "2.33.1" +name = "concurrent-queue" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129" +checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" dependencies = [ - "ansi_term", - "atty", - "bitflags", - "strsim", - "textwrap", - "unicode-width", - "vec_map", + "cache-padded", ] [[package]] -name = "concurrent-queue" -version = "1.1.1" +name = "const_fn" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83c06aff61f2d899eb87c379df3cbf7876f14471dcab474e0b6dc90ab96c080" -dependencies = [ - "cache-padded", -] +checksum = "f92cfa0fd5690b3cf8c1ef2cabbd9b7ef22fa53cf5e1f92b05103f6d5d1cf6e7" + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" [[package]] name = "cookie" -version = "0.14.1" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca761767cf3fa9068cc893ec8c247a22d0fd0535848e65640c0548bd1f8bbb36" +checksum = "03a5d7b21829bc7b4bf4754a978a241ae54ea55a40f92bb20216e54096f4b951" dependencies = [ "aes-gcm", - "base64", + "base64 0.13.0", "hkdf", - "hmac", + "hmac 0.10.1", "percent-encoding", - "rand 0.7.3", + "rand 0.8.4", "sha2", - "time", + "time 0.2.27", + "version_check", ] +[[package]] +name = "cpufeatures" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" +dependencies = [ + "libc", +] + +[[package]] +name = "cpuid-bool" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" + [[package]] name = "crossbeam-queue" -version = "0.2.3" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" +checksum = "9b10ddc024425c88c2ad148c1b0fd53f4c6d38db9697c9f1588381212fa657c9" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "crossbeam-utils", - "maybe-uninit", ] [[package]] name = "crossbeam-utils" -version = "0.7.2" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" dependencies = [ - "autocfg", - "cfg-if", + "cfg-if 1.0.0", "lazy_static", ] [[package]] name = "crypto-mac" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" dependencies = [ "generic-array", - "subtle 1.0.0", + "subtle", ] [[package]] -name = "data-encoding" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72aa14c04dfae8dd7d8a2b1cb7ca2152618cd01336dbfe704b8dcbf8d41dbd69" - -[[package]] -name = "digest" -version = "0.8.1" +name = "crypto-mac" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +checksum = "bff07008ec701e8028e2ceb8f83f0e4274ee62bd2dbdc4fefff2e9a91824081a" dependencies = [ "generic-array", + "subtle", ] [[package]] -name = "discard" -version = "1.0.4" +name = "ctor" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" +checksum = "ccc0a48a9b826acdf4028595adc9db92caea352f7af011a3034acd172a52a0aa" +dependencies = [ + "quote", + "syn", +] [[package]] -name = "dtoa" -version = "0.4.6" +name = "ctr" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134951f4028bdadb9b84baf4232681efbf277da25144b9b0ad65df75946c422b" +checksum = "fb4a30d54f7443bf3d6191dcd486aca19e67cb3c49fa7a06a319966346707e7f" +dependencies = [ + "cipher", +] [[package]] -name = "env_logger" -version = "0.7.1" +name = "dashmap" +version = "4.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" dependencies = [ - "atty", - "humantime", - "log", - "regex", - "termcolor", + "cfg-if 1.0.0", + "num_cpus", ] [[package]] -name = "error-chain" -version = "0.12.2" +name = "digest" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d371106cc88ffdfb1eabd7111e432da544f16f3e2d7bf1dfe8bf575f1df045cd" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "backtrace", - "version_check", + "generic-array", ] [[package]] -name = "fake-simd" -version = "0.1.2" +name = "discard" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" + +[[package]] +name = "event-listener" +version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" +checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59" [[package]] name = "fastrand" -version = "1.3.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36a9cb09840f81cd211e435d00a4e487edd263dc3c8ff815c32dd76ad668ebed" +checksum = "b394ed3d285a429378d3b384b9eb1285267e7df4b166df24b7a6939a04dc392e" +dependencies = [ + "instant", +] [[package]] name = "femme" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b6b21baebbed15551f2170010ca4101b9ed3fdc05822791c8bd4631840eab81" +checksum = "2af1a24f391a5a94d756db5092c6576aad494b88a71a5a36b20c67b63e0df034" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "js-sys", "log", - "serde 1.0.114", + "serde", "serde_derive", + "serde_json", "wasm-bindgen", "web-sys", ] [[package]] name = "ffmpeg-sys-next" -version = "4.3.0" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01bba495d04757f7a3e471b3e411759a8968571c4618235bc1c9e1099b4a84d1" +checksum = "de57234f2c49c6e093fe67bbbaa9142c228f6e2d5533ef27980993d5b6adef2a" dependencies = [ "bindgen", "cc", "libc", "num_cpus", "pkg-config", - "regex", + "vcpkg", ] [[package]] -name = "fuchsia-cprng" -version = "0.1.1" +name = "form_urlencoded" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + +[[package]] +name = "funty" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" + +[[package]] +name = "futures" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] [[package]] name = "futures-channel" -version = "0.3.5" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f366ad74c28cca6ba456d95e6422883cfb4b252a83bed929c83abfdbbf2967d5" +checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" dependencies = [ "futures-core", "futures-sink", @@ -527,91 +763,135 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.5" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59f5fff90fd5d971f936ad674802482ba441b6f09ba5e15fd8b39145582ca399" +checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" + +[[package]] +name = "futures-executor" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] [[package]] name = "futures-io" -version = "0.3.5" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de27142b013a8e869c14957e6d2edeef89e97c289e69d042ee3a49acd8b51789" +checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377" [[package]] -name = "futures-sink" -version = "0.3.5" +name = "futures-lite" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f2032893cb734c7a05d85ce0cc8b8c4075278e93b24b66f9de99d6eb0fa8acc" +checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite 0.2.7", + "waker-fn", +] [[package]] -name = "futures-task" -version = "0.3.5" +name = "futures-macro" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb66b5f09e22019b1ab0830f7785bcea8e7a42148683f99214f73f8ec21a626" +checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb" dependencies = [ - "once_cell", + "autocfg", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn", ] +[[package]] +name = "futures-sink" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11" + +[[package]] +name = "futures-task" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" + [[package]] name = "futures-timer" version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" -dependencies = [ - "gloo-timers", - "send_wrapper", -] [[package]] name = "futures-util" -version = "0.3.5" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8764574ff08b701a084482c3c7031349104b07ac897393010494beaa18ce32c6" +checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" dependencies = [ + "autocfg", + "futures-channel", "futures-core", "futures-io", + "futures-macro", "futures-sink", "futures-task", "memchr", - "pin-project", + "pin-project-lite 0.2.7", "pin-utils", + "proc-macro-hack", + "proc-macro-nested", "slab", ] [[package]] name = "generic-array" -version = "0.12.3" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" +checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" dependencies = [ "typenum", + "version_check", ] [[package]] name = "getrandom" -version = "0.1.14" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", - "wasi", + "wasi 0.9.0+wasi-snapshot-preview1", ] [[package]] -name = "ghash" +name = "getrandom" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f0930ed19a7184089ea46d2fedead2f6dc2b674c5db4276b7da336c7cd83252" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ - "polyval", + "cfg-if 1.0.0", + "libc", + "wasi 0.10.2+wasi-snapshot-preview1", ] [[package]] -name = "gimli" -version = "0.22.0" +name = "ghash" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724" +checksum = "97304e4cd182c3846f7575ced3890c53012ce534ad9114046b0a9e00bb30a375" +dependencies = [ + "opaque-debug", + "polyval", +] [[package]] name = "glob" @@ -634,46 +914,72 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.14" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9586eedd4ce6b3c498bc3b4dd92fc9f11166aa908a914071953768066c67909" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "libc", ] [[package]] -name = "hkdf" -version = "0.8.0" +name = "hkdf" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51ab2f639c231793c5f6114bdb9bbe50a7dbbfcd7c7c6bd8475dec2d991e964f" +dependencies = [ + "digest", + "hmac 0.10.1", +] + +[[package]] +name = "hmac" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fa08a006102488bd9cd5b8013aabe84955cf5ae22e304c2caf655b633aefae3" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" dependencies = [ + "crypto-mac 0.8.0", "digest", - "hmac", ] [[package]] name = "hmac" -version = "0.7.1" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695" +checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" dependencies = [ - "crypto-mac", + "crypto-mac 0.10.1", "digest", ] +[[package]] +name = "http-client" +version = "6.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea880b03c18a7e981d7fb3608b8904a98425d53c440758fcebf7d934aa56547c" +dependencies = [ + "async-trait", + "cfg-if 1.0.0", + "dashmap", + "http-types", + "log", +] + [[package]] name = "http-types" -version = "2.2.1" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca4221cd1c7cedf275cd0ad3c9dfe58b5acc93cdd5511c7e020a102e1995fe99" +checksum = "6e9b187a72d63adbfba487f48095306ac823049cb504ee195541e91c7775f5ad" dependencies = [ "anyhow", + "async-channel", "async-std", + "base64 0.13.0", "cookie", + "futures-lite", "infer", - "pin-project-lite", + "pin-project-lite 0.2.7", "rand 0.7.3", - "serde 1.0.114", + "serde", "serde_json", "serde_qs", "serde_urlencoded", @@ -682,24 +988,21 @@ dependencies = [ [[package]] name = "httparse" -version = "1.3.4" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" +checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" [[package]] -name = "humantime" -version = "1.3.0" +name = "humansize" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" -dependencies = [ - "quick-error", -] +checksum = "02296996cb8796d7c6e3bc2d9211b7802812d36999a51bb754123ead7d37d026" [[package]] name = "idna" -version = "0.2.0" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" dependencies = [ "matches", "unicode-bidi", @@ -708,21 +1011,30 @@ dependencies = [ [[package]] name = "infer" -version = "0.1.7" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e9829a50b42bb782c1df523f78d332fe371b10c661e78b7a3c34b0198e9fac" + +[[package]] +name = "instant" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6854dd77ddc4f9ba1a448f487e27843583d407648150426a30c2ea3a2c39490a" +checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d" +dependencies = [ + "cfg-if 1.0.0", +] [[package]] name = "itoa" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] name = "js-sys" -version = "0.3.41" +version = "0.3.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4b9172132a62451e56142bff9afc91c8e4a4500aa5b847da36815b63bfda916" +checksum = "1866b355d9c878e5e607473cbe3f63282c0b7aad2db1dbebf55076c686918254" dependencies = [ "wasm-bindgen", ] @@ -744,15 +1056,28 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "lazycell" -version = "1.2.1" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "lexical-core" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" +checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" +dependencies = [ + "arrayvec", + "bitflags", + "cfg-if 1.0.0", + "ryu", + "static_assertions", +] [[package]] name = "libc" -version = "0.2.71" +version = "0.2.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" +checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21" [[package]] name = "libloading" @@ -766,55 +1091,54 @@ dependencies = [ [[package]] name = "log" -version = "0.4.8" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", + "value-bag", ] [[package]] name = "matches" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" - -[[package]] -name = "maybe-uninit" -version = "2.0.0" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "memchr" -version = "2.3.3" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] -name = "miniz_oxide" -version = "0.4.0" +name = "nom" +version = "5.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be0f75932c1f6cfae3c04000e40114adf955636e19040f9c0a2c380702aa1c7f" +checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" dependencies = [ - "adler", + "memchr", + "version_check", ] [[package]] name = "nom" -version = "5.1.2" +version = "6.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" +checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2" dependencies = [ + "bitvec", + "funty", + "lexical-core", "memchr", "version_check", ] [[package]] name = "num-bigint" -version = "0.3.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7f3fc75e3697059fb1bc465e3d8cca6cf92f56854f201158b3f9c77d5a3cfa0" +checksum = "74e768dff5fb39a41b3bcd30bb25cf989706c90d028d1ad71971987aa309d535" dependencies = [ "autocfg", "num-integer", @@ -823,9 +1147,9 @@ dependencies = [ [[package]] name = "num-integer" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" dependencies = [ "autocfg", "num-traits", @@ -833,9 +1157,9 @@ dependencies = [ [[package]] name = "num-rational" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5b4d7360f362cfb50dde8143501e6940b22f644be75a4cc90b2d81968908138" +checksum = "d41702bd167c2df5520b384281bc111a4b5efcf7fbc4c9c222c815b07e0a6a6a" dependencies = [ "autocfg", "num-bigint", @@ -845,9 +1169,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" dependencies = [ "autocfg", ] @@ -862,29 +1186,23 @@ dependencies = [ "libc", ] -[[package]] -name = "object" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5" - [[package]] name = "once_cell" -version = "1.4.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d" +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" [[package]] name = "opaque-debug" -version = "0.2.3" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "parking" -version = "1.0.4" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efcee3c6d23b94012e240525f131c6abaa9e5eeb8f211002d93beec3b7be350" +checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" [[package]] name = "peeking_take_while" @@ -900,18 +1218,18 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" [[package]] name = "pin-project" -version = "0.4.22" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12e3a6cdbfe94a5e4572812a0201f8c0ed98c1c452c7b8563ce2276988ef9c17" +checksum = "576bc800220cc65dac09e99e97b08b358cfab6e17078de8dc5fee223bd2d0c08" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "0.4.22" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a0ffd45cf79d88737d7cc85bfd5d2894bee1139b356e616fe85dc389c61aaf7" +checksum = "6e8fe8163d14ce7f0cdac2e040116f22eac817edabff0be91e8aff7e9accf389" dependencies = [ "proc-macro2", "quote", @@ -920,9 +1238,15 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.1.7" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" + +[[package]] +name = "pin-project-lite" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282adbf10f2698a7a77f8e983a74b2d18176c19a7fd32a45446139ae7b02b715" +checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" [[package]] name = "pin-utils" @@ -932,90 +1256,99 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.17" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" + +[[package]] +name = "polling" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" +checksum = "92341d779fa34ea8437ef4d82d440d5e1ce3f3ff7f824aa64424cd481f9a1f25" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "log", + "wepoll-ffi", + "winapi", +] [[package]] name = "polyval" -version = "0.3.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ec3341498978de3bfd12d1b22f1af1de22818f5473a11e8a6ef997989e3a212" +checksum = "eebcc4aa140b9abd2bc40d9c3f7ccec842679cd79045ac3a7ac698c1a064b7cd" dependencies = [ - "cfg-if", + "cpuid-bool", + "opaque-debug", "universal-hash", ] [[package]] name = "ppv-lite86" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "proc-macro-hack" -version = "0.5.16" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" + +[[package]] +name = "proc-macro-nested" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e0456befd48169b9f13ef0f0ad46d492cf9d2dbb918bcf38e01eed4ce3ec5e4" +checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" [[package]] name = "proc-macro2" -version = "1.0.18" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa" +checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" dependencies = [ "unicode-xid", ] -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - [[package]] name = "quote" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" dependencies = [ "proc-macro2", ] [[package]] -name = "rand" -version = "0.3.23" +name = "radium" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" -dependencies = [ - "libc", - "rand 0.4.6", -] +checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" [[package]] name = "rand" -version = "0.4.6" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "fuchsia-cprng", + "getrandom 0.1.16", "libc", - "rand_core 0.3.1", - "rdrand", - "winapi", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc 0.2.0", ] [[package]] name = "rand" -version = "0.7.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" dependencies = [ - "getrandom", "libc", - "rand_chacha", - "rand_core 0.5.1", - "rand_hc", + "rand_chacha 0.3.1", + "rand_core 0.6.3", + "rand_hc 0.3.1", ] [[package]] @@ -1029,27 +1362,31 @@ dependencies = [ ] [[package]] -name = "rand_core" +name = "rand_chacha" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ - "rand_core 0.4.2", + "ppv-lite86", + "rand_core 0.6.3", ] [[package]] name = "rand_core" -version = "0.4.2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] [[package]] name = "rand_core" -version = "0.5.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ - "getrandom", + "getrandom 0.2.3", ] [[package]] @@ -1062,49 +1399,34 @@ dependencies = [ ] [[package]] -name = "rdrand" -version = "0.4.0" +name = "rand_hc" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" dependencies = [ - "rand_core 0.3.1", + "rand_core 0.6.3", ] -[[package]] -name = "redox_syscall" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" - [[package]] name = "regex" -version = "1.3.9" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" dependencies = [ - "aho-corasick", - "memchr", "regex-syntax", - "thread_local", ] [[package]] name = "regex-syntax" -version = "0.6.18" +version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "route-recognizer" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea509065eb0b3c446acdd0102f0d46567dc30902dc0be91d6552035d92b0f4f8" - -[[package]] -name = "rustc-demangle" -version = "0.1.16" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" +checksum = "56770675ebc04927ded3e60633437841581c285dc6236109ea25fbf3beb7b59e" [[package]] name = "rustc-hash" @@ -1127,12 +1449,6 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" -[[package]] -name = "scoped-tls" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" - [[package]] name = "semver" version = "0.9.0" @@ -1148,32 +1464,20 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -[[package]] -name = "send_wrapper" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" - -[[package]] -name = "serde" -version = "0.9.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34b623917345a631dc9608d5194cc206b3fe6c3554cd1c75b937e55e285254af" - [[package]] name = "serde" -version = "1.0.114" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3" +checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.114" +version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0be94b04690fbaed37cddffc5c134bf537c8e3329d53e982fe04c374978f8e" +checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" dependencies = [ "proc-macro2", "quote", @@ -1182,37 +1486,36 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.56" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3433e879a558dde8b5e8feb2a04899cf34fdde1fafb894687e52105fc1162ac3" +checksum = "a7f9e390c27c3c0ce8bc5d725f6e4d30a29d26659494aa4b17535f7522c5c950" dependencies = [ "itoa", "ryu", - "serde 1.0.114", + "serde", ] [[package]] name = "serde_qs" -version = "0.6.1" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6f3acf84e23ab27c01cb5917551765c01c50b2000089db8fa47fe018a3260cf" +checksum = "d8a72808528a89fa9eca23bbb6a1eb92cb639b881357269b6510f11e50c0f8a9" dependencies = [ - "data-encoding", - "error-chain", "percent-encoding", - "serde 1.0.114", + "serde", + "thiserror", ] [[package]] name = "serde_urlencoded" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ec5d77e2d4c73717816afac02670d5c4f534ea95ed430442cad02e7a6e32c97" +checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" dependencies = [ - "dtoa", + "form_urlencoded", "itoa", - "serde 1.0.114", - "url", + "ryu", + "serde", ] [[package]] @@ -1223,13 +1526,14 @@ checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" [[package]] name = "sha2" -version = "0.8.2" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" +checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" dependencies = [ "block-buffer", + "cfg-if 1.0.0", + "cpufeatures", "digest", - "fake-simd", "opaque-debug", ] @@ -1240,59 +1544,70 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" [[package]] -name = "slab" -version = "0.4.2" +name = "signal-hook" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +checksum = "9c98891d737e271a2954825ef19e46bd16bdb98e2746f2eec4f7a4ef7946efd1" +dependencies = [ + "libc", + "signal-hook-registry", +] [[package]] -name = "smol" -version = "0.1.18" +name = "signal-hook-registry" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "620cbb3c6e34da57d3a248cda0cd01cd5848164dc062e764e65d06fe3ea7aed5" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" dependencies = [ - "async-task", - "blocking", - "concurrent-queue", - "fastrand", - "futures-io", - "futures-util", "libc", - "once_cell", - "scoped-tls", - "slab", - "socket2", - "wepoll-sys-stjepang", - "winapi", ] +[[package]] +name = "simple-mutex" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38aabbeafa6f6dead8cebf246fe9fae1f9215c8d29b3a69f93bd62a9e4a3dcd6" +dependencies = [ + "event-listener", +] + +[[package]] +name = "slab" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590" + [[package]] name = "socket2" -version = "0.3.12" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918" +checksum = "765f090f0e423d2b55843402a07915add955e7d60657db13707a159727326cad" dependencies = [ - "cfg-if", "libc", - "redox_syscall", "winapi", ] [[package]] name = "stable_deref_trait" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "standback" -version = "0.2.9" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0437cfb83762844799a60e1e3b489d5ceb6a650fbacb86437badc1b6d87b246" +checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" dependencies = [ "version_check", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "stdweb" version = "0.4.20" @@ -1315,7 +1630,7 @@ checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" dependencies = [ "proc-macro2", "quote", - "serde 1.0.114", + "serde", "serde_derive", "syn", ] @@ -1329,7 +1644,7 @@ dependencies = [ "base-x", "proc-macro2", "quote", - "serde 1.0.114", + "serde", "serde_derive", "serde_json", "sha1", @@ -1342,29 +1657,23 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" -[[package]] -name = "strsim" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" - [[package]] name = "subtle" -version = "1.0.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] -name = "subtle" -version = "2.2.3" +name = "sval" +version = "1.0.0-alpha.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "502d53007c02d7605a05df1c1a73ee436952781653da5d0bf57ad608f66932c1" +checksum = "45f6ee7c7b87caf59549e9fe45d6a69c75c8019e79e212a835c5da0e92f0ba08" [[package]] name = "syn" -version = "1.0.33" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8d5d96e8cbb005d6959f119f773bfaebb5684296108fb32600c00cde305b2cd" +checksum = "c6f107db402c2c2055242dbf4d2af0e69197202e9faacbef9571bbe47f5a1b84" dependencies = [ "proc-macro2", "quote", @@ -1372,56 +1681,71 @@ dependencies = [ ] [[package]] -name = "termcolor" -version = "1.1.0" +name = "tap" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" -dependencies = [ - "winapi-util", -] +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] -name = "textwrap" -version = "0.11.0" +name = "thiserror" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88" dependencies = [ - "unicode-width", + "thiserror-impl", ] [[package]] -name = "thread_local" -version = "1.0.1" +name = "thiserror-impl" +version = "1.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" +checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c" dependencies = [ - "lazy_static", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "tide" -version = "0.11.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "151b07f369a9152c2f93715ea0db8a7f7e2533bd2e52fbff1ea5bad7a88db541" +checksum = "c459573f0dd2cc734b539047f57489ea875af8ee950860ded20cf93a79a1dee0" dependencies = [ "async-h1", + "async-session", "async-sse", "async-std", + "async-trait", "femme", + "futures-util", + "http-client", "http-types", "kv-log-macro", + "log", + "pin-project-lite 0.2.7", "route-recognizer", - "serde 1.0.114", + "serde", "serde_json", ] [[package]] name = "time" -version = "0.2.16" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "time" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a51cadc5b1eec673a685ff7c33192ff7b7603d0b75446fb354939ee615acb15" +checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" dependencies = [ - "cfg-if", + "const_fn", "libc", "standback", "stdweb", @@ -1432,9 +1756,9 @@ dependencies = [ [[package]] name = "time-macros" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ae9b6e9f095bc105e183e3cd493d72579be3181ad4004fceb01adbe9eecab2d" +checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" dependencies = [ "proc-macro-hack", "time-macros-impl", @@ -1442,9 +1766,9 @@ dependencies = [ [[package]] name = "time-macros-impl" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5c3be1edfad6027c69f5491cf4cb310d1a71ecd6af742788c6ff8bced86b8fa" +checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" dependencies = [ "proc-macro-hack", "proc-macro2", @@ -1455,108 +1779,134 @@ dependencies = [ [[package]] name = "tinyvec" -version = "0.3.3" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5241dd6f21443a3606b432718b166d3cedc962fd4b8bea54a8bc7f514ebda986" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "toml" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53953d2d3a5ad81d9f844a32f14ebb121f50b650cd59d0ee2a07cf13c617efed" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +dependencies = [ + "serde", +] [[package]] name = "transotf" version = "0.1.0" dependencies = [ + "askama", "async-std", "byteorder", "ffmpeg-sys-next", + "futures", + "futures-timer", "http-types", "lazy_static", "num-rational", + "serde", "tide", "uuid", ] [[package]] name = "typenum" -version = "1.12.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" +checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" [[package]] name = "unicode-bidi" -version = "0.3.4" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -dependencies = [ - "matches", -] +checksum = "246f4c42e67e7a4e3c6106ff716a5d067d4132a642840b242e357e468a2a0085" [[package]] name = "unicode-normalization" -version = "0.1.13" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb19cf769fa8c6a80a162df694621ebeb4dafb606470b2b2fce0be40a98a977" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" dependencies = [ "tinyvec", ] -[[package]] -name = "unicode-width" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" - [[package]] name = "unicode-xid" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "universal-hash" -version = "0.3.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0c900f2f9b4116803415878ff48b63da9edb268668e08cf9292d7503114a01" +checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" dependencies = [ "generic-array", - "subtle 2.2.3", + "subtle", ] [[package]] name = "url" -version = "2.1.1" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" dependencies = [ + "form_urlencoded", "idna", "matches", "percent-encoding", + "serde", ] [[package]] name = "uuid" -version = "0.4.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cfec50b0842181ba6e713151b72f4ec84a6a7e2c9c8a8a3ffc37bb1cd16b231" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" dependencies = [ - "rand 0.3.23", - "serde 0.9.15", + "getrandom 0.2.3", + "serde", ] [[package]] -name = "vec_map" -version = "0.8.2" +name = "value-bag" +version = "1.0.0-alpha.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd320e1520f94261153e96f7534476ad869c14022aee1e59af7c778075d840ae" +dependencies = [ + "ctor", + "sval", + "version_check", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" [[package]] name = "waker-fn" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9571542c2ce85ce642e6b58b3364da2fb53526360dfb7c211add4f5c23105ff7" +checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" [[package]] name = "wasi" @@ -1564,23 +1914,29 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + [[package]] name = "wasm-bindgen" -version = "0.2.64" +version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a634620115e4a229108b71bde263bb4220c483b3f07f5ba514ee8d15064c4c2" +checksum = "5e68338db6becec24d3c7977b5bf8a48be992c934b5d07177e3931f5dc9b076c" dependencies = [ - "cfg-if", - "serde 1.0.114", + "cfg-if 1.0.0", + "serde", "serde_json", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.64" +version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e53963b583d18a5aa3aaae4b4c1cb535218246131ba22a71f05b518098571df" +checksum = "f34c405b4f0658583dba0c1c7c9b694f3cac32655db463b56c254a1c75269523" dependencies = [ "bumpalo", "lazy_static", @@ -1593,11 +1949,11 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.14" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dba48d66049d2a6cc8488702e7259ab7afc9043ad0dc5448444f46f2a453b362" +checksum = "a87d738d4abc4cf22f6eb142f5b9a81301331ee3c767f2fef2fda4e325492060" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "js-sys", "wasm-bindgen", "web-sys", @@ -1605,9 +1961,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.64" +version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fcfd5ef6eec85623b4c6e844293d4516470d8f19cd72d0d12246017eb9060b8" +checksum = "b9d5a6580be83b19dc570a8f9c324251687ab2184e57086f71625feb57ec77c8" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1615,9 +1971,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.64" +version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9adff9ee0e94b926ca81b57f57f86d5545cdcb1d259e21ec9bdd95b901754c75" +checksum = "e3775a030dc6f5a0afd8a84981a21cc92a781eb429acef9ecce476d0c9113e92" dependencies = [ "proc-macro2", "quote", @@ -1628,43 +1984,34 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.64" +version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7b90ea6c632dd06fd765d44542e234d5e63d9bb917ecd64d79778a13bd79ae" +checksum = "c279e376c7a8e8752a8f1eaa35b7b0bee6bb9fb0cdacfa97cc3f1f289c87e2b4" [[package]] name = "web-sys" -version = "0.3.41" +version = "0.3.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "863539788676619aac1a23e2df3655e96b32b0e05eb72ca34ba045ad573c625d" +checksum = "0a84d70d1ec7d2da2d26a5bd78f4bca1b8c3254805363ce743b7a05bc30d195a" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] -name = "wepoll-sys-stjepang" -version = "1.0.6" +name = "wepoll-ffi" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fd319e971980166b53e17b1026812ad66c6b54063be879eb182342b55284694" +checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" dependencies = [ "cc", ] -[[package]] -name = "which" -version = "3.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724" -dependencies = [ - "libc", -] - [[package]] name = "winapi" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", @@ -1676,15 +2023,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -1692,7 +2030,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "zeroize" -version = "1.1.0" +name = "wyz" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cbac2ed2ba24cc90f5e06485ac8c7c1e5449fe8911aef4d8877218af021a5b8" +checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" diff --git a/Cargo.toml b/Cargo.toml index 080ea41..6bb7fac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,19 +6,31 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + + [dependencies] -num-rational = "0.3.0" -byteorder = "1.3.4" -tide = "0.11.0" +num-rational = "0.4.0" +byteorder = "1.4.3" +tide = "0.16.0" lazy_static = "1.4.0" -async-std = { version = "1.6.2", features = ["attributes"] } -uuid = { version = "0.4", features = ["serde", "v4"] } -http-types = "2.2.1" +uuid = { version = "0.8.2", features = ["serde", "v4"] } +http-types = "2.12.0" +futures = "0.3.17" +serde = { version = "1.0.130", features = ["derive"] } +futures-timer = { version = "3.0.2", default-features = false, features = [] } +async-std = { version = "1.10.0", features = ["attributes"] } +askama = "0.10.5" +# Fix for dependencies that do not matter [dependencies.ffmpeg-sys-next] -version = "4.3.0" +version = "4.4.0" features = ["avcodec", "avdevice", "avfilter", "avformat", "swresample", "swscale"] + +# Fix for not depending on WASM shit +#[patch.crates-io] +#async-std = { path = "/home/eater/shit/async-std" } + #[dependencies.ffmpeg-next] #version = "4.3.0" #default-features = false diff --git a/resources/favicon.ico b/resources/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..329978f1969f9791505a299cd85db463075b10ec GIT binary patch literal 67646 zcmeI(u?Ye}5J1r}vjSs7OA>6xKCD2n0Kvcxyb{a>Lk$!e_Y|#RVcy9ccN@vy7v4rp z+Hbv%cAv*$I*D0CEZVfCaq+W0K7L-l5C8k)v`V7^0}L?000Rs#zyJdbFu(u<3^2d| z0}L?000Rs#zyJdbFu(u<3^2d|0}L?000Rs#zyJdbFu(uCAC1r$&~0R_Rrl=Ixc9xE zPxSxn5d#b`zyJdbFu(u<3^2d|0}L?000Rs#zyJdbFu(u<3^2d|0}L?000Rs#zyJdb zFu(u<3^4FBaBts$o2m`Y$4#2L4W7d?P2C2M(<+Sy3^2d|0}L?000Rs#zyJdbFu(u< z3^2d|0}L?000Rs#zyJdbFu(u<3^2d|0}L?000Rs#zyJdb^lczq3Mim}0tzTluD~0t Cdyd`! literal 0 HcmV?d00001 diff --git a/resources/player.html b/resources/player.html new file mode 100644 index 0000000..b859cbd --- /dev/null +++ b/resources/player.html @@ -0,0 +1,67 @@ + + + + + DASH Test + + + + + + + + + + \ No newline at end of file diff --git a/src/av/format.rs b/src/av/format.rs index 788c735..bb51346 100644 --- a/src/av/format.rs +++ b/src/av/format.rs @@ -39,15 +39,25 @@ impl Format { } impl Format { - pub fn seek(&self, seconds: u32, stream: Option<&Stream>) -> Result<(), String> { + pub fn seek( + &self, + seconds: u32, + stream_index: Option, + backwards: bool, + ) -> Result<(), String> { let seconds: i32 = seconds as i32; - let time_base = stream.map(|s| s.time_base().den()).unwrap_or(AV_TIME_BASE); + let time_base = stream_index + .map(|si| self.stream(None, Some(si), None)) + .unwrap_or(Ok(None))? + .map(|s| s.time_base().den()) + .unwrap_or(AV_TIME_BASE); + verify_response("Failed to seek", unsafe { av_seek_frame( self.ctx, - stream.map(|s| s.index()).unwrap_or(-1), + stream_index.unwrap_or(-1), (seconds * time_base) as i64, - AVSEEK_FLAG_BACKWARD, + if backwards { AVSEEK_FLAG_BACKWARD } else { 0 }, ) })?; @@ -56,7 +66,7 @@ impl Format { pub fn stream( &self, - stream_type: AVMediaType, + stream_type: Option, index: Option, related: Option, ) -> Result, String> { @@ -66,16 +76,20 @@ impl Format { let index = if let Some(index) = index { index - } else { + } else if let Some(stream_type) = stream_type { verify_response( "Failed finding best stream", av_find_best_stream(ctx, stream_type, -1, related.unwrap_or(-1), null_mut(), 0), )? + } else { + 0 }; for _ in 0..(*ctx).nb_streams { let curr_stream = *stream; - if (*(*curr_stream).codecpar).codec_type == stream_type { + if stream_type.is_none() + || Some((*(*curr_stream).codecpar).codec_type) == stream_type + { if (*curr_stream).index == index { return Ok(Some(Stream(curr_stream))); } @@ -131,7 +145,8 @@ impl Format { pub fn write_packet_null(&self) -> Result<(), String> { verify_response("failed to write to output", unsafe { av_write_frame(self.as_mut_ptr(), null_mut()) - })?; + }) + .unwrap(); Ok(()) } @@ -147,7 +162,8 @@ impl Format { pub fn write_packet(&self, packet: &Packet) -> Result<(), String> { verify_response("failed to write to output", unsafe { av_write_frame(self.as_mut_ptr(), packet.as_mut_ptr()) - })?; + }) + .unwrap(); Ok(()) } diff --git a/src/av/mod.rs b/src/av/mod.rs index 5e74151..945da46 100644 --- a/src/av/mod.rs +++ b/src/av/mod.rs @@ -1,10 +1,9 @@ use crate::av_err2str; use ffmpeg_sys_next::AVCodecID::AV_CODEC_ID_HEVC; use ffmpeg_sys_next::{ - av_codec_is_decoder, av_codec_is_encoder, av_codec_next, av_inv_q, av_log_set_level, - av_register_all, avcodec_alloc_context3, avcodec_find_decoder_by_name, - avcodec_find_encoder_by_name, AVCodec, AVCodecContext, AVCodecID, AVRational, - AV_CODEC_CAP_HARDWARE, + av_codec_is_decoder, av_codec_is_encoder, av_codec_next, av_inv_q, av_register_all, + avcodec_alloc_context3, avcodec_find_decoder_by_name, avcodec_find_encoder_by_name, AVCodec, + AVCodecContext, AVCodecID, AVRational, AV_CODEC_CAP_HARDWARE, }; use num_rational::Ratio; use std::any::type_name; @@ -214,7 +213,7 @@ fn remove_if_exists(list: &mut Vec, needle: &str, to_remove: Vec<&s pub fn init() { unsafe { av_register_all(); - av_log_set_level(-8); + // av_log_set_level(-8); } } @@ -271,6 +270,16 @@ pub trait Rational { } fn simplify(&self) -> Self; + + #[inline] + fn as_f64(&self) -> f64 { + self.num() as f64 / self.den() as f64 + } + + #[inline] + fn as_f32(&self) -> f32 { + self.num() as f32 / self.den() as f32 + } } impl Rational for Ratio { diff --git a/src/av/stream.rs b/src/av/stream.rs index 58b68d9..3ec0c6d 100644 --- a/src/av/stream.rs +++ b/src/av/stream.rs @@ -7,8 +7,9 @@ use crate::av::encoder_selector::EncoderSelector; use crate::av::format::Format; use crate::av::xcoder::XCoder; use crate::av::{get_best_decoder, get_best_encoder, Rational}; -use ffmpeg_sys_next::{av_guess_frame_rate, AVCodecID, AVRational, AVStream}; +use ffmpeg_sys_next::{av_guess_frame_rate, avcodec_get_name, AVCodecID, AVRational, AVStream}; use num_rational::Ratio; +use std::ffi::CStr; use std::ptr::null_mut; pub struct Stream(pub *mut AVStream); @@ -63,6 +64,15 @@ impl Stream { unsafe { (*(*self.0).codec).codec_id } } + pub fn codec_name(&self) -> String { + unsafe { + CStr::from_ptr(avcodec_get_name(self.codec())) + .to_str() + .unwrap() + .to_string() + } + } + pub fn params(&self) -> CodecParameters { unsafe { CodecParameters((*self.0).codecpar) } } @@ -82,11 +92,21 @@ impl Stream { unsafe { (*self.as_ptr()).sample_aspect_ratio } } + #[inline] + pub fn duration(&self) -> i64 { + unsafe { (*self.as_ptr()).duration } + } + + pub fn frame_count(&self) -> i64 { + unsafe { (*self.as_ptr()).nb_frames } + } + #[inline] pub fn set_sample_aspect_ratio(&self, sample_aspect_ratio: impl Rational) { unsafe { (*self.as_mut_ptr()).sample_aspect_ratio = sample_aspect_ratio.to_av() } } + #[inline] pub fn avg_frame_rate(&self, fmt: &Format) -> Option { Some(unsafe { av_guess_frame_rate(fmt.as_mut_ptr(), self.as_mut_ptr(), null_mut()) }) } diff --git a/src/av/xcoder.rs b/src/av/xcoder.rs index 32309ef..19ac1cd 100644 --- a/src/av/xcoder.rs +++ b/src/av/xcoder.rs @@ -4,7 +4,8 @@ use crate::av::{verify_response, Rational}; use crate::av_err2str; use ffmpeg_sys_next::AVPixelFormat::AV_PIX_FMT_NONE; use ffmpeg_sys_next::{ - av_malloc, avcodec_flush_buffers, avcodec_open2, AVCodecContext, AVCodecID, AVColorPrimaries, + av_free, av_get_channel_layout_string, av_get_pix_fmt_name, av_get_sample_fmt_name, av_malloc, + avcodec_flush_buffers, avcodec_open2, AVCodecContext, AVCodecID, AVColorPrimaries, AVColorRange, AVColorTransferCharacteristic, AVPixelFormat, AVRational, AVSampleFormat, AVERROR, AVERROR_EOF, EAGAIN, }; @@ -72,6 +73,16 @@ pub trait XCoder: Sized { unsafe { (*self.as_ptr()).pix_fmt } } + #[inline] + fn pixel_format_name(&self) -> String { + unsafe { + CStr::from_ptr(av_get_pix_fmt_name(self.pixel_format())) + .to_str() + .unwrap() + .to_string() + } + } + #[inline] fn set_pixel_format(&self, pixel_format: AVPixelFormat) { unsafe { (*self.as_mut_ptr()).pix_fmt = pixel_format } @@ -164,11 +175,32 @@ pub trait XCoder: Sized { unsafe { (*self.as_mut_ptr()).channel_layout = channel_layout } } + fn channel_layout_name(&self) -> String { + unsafe { + let str = av_malloc(1024).cast(); + av_get_channel_layout_string(str, 1024, self.channels(), self.channel_layout()); + let string = CStr::from_ptr(str).to_str().unwrap().to_string(); + av_free(str.cast()); + + string + } + } + #[inline] fn sample_format(&self) -> AVSampleFormat { unsafe { (*self.as_ptr()).sample_fmt } } + #[inline] + fn sample_format_name(&self) -> String { + unsafe { + CStr::from_ptr(av_get_sample_fmt_name(self.sample_format())) + .to_str() + .unwrap() + .to_string() + } + } + #[inline] fn set_sample_format(&self, sample_format: AVSampleFormat) { unsafe { (*self.as_mut_ptr()).sample_fmt = sample_format } diff --git a/src/main.rs b/src/main.rs index ae742b8..d6a7b68 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,17 +2,20 @@ use crate::av::init; use crate::transcoder_manager::{TranscoderInstance, TranscoderManager}; +use askama::Template; use async_std::fs::File; use async_std::sync::{Arc, RwLock}; use ffmpeg_sys_next::{av_make_error_string, av_malloc, av_version_info}; use http_types::Error as HttpError; use lazy_static::lazy_static; +use serde::Serialize; use std::collections::HashMap; use std::ffi::{CStr, CString}; +use std::ops::Deref; use std::option::Option::Some; use std::os::raw::{c_char, c_int}; use std::str::FromStr; -use tide::{Request, StatusCode}; +use tide::{Body, Request, Response, StatusCode}; use uuid::Uuid; pub mod av; @@ -20,8 +23,6 @@ pub mod transcoder; pub mod transcoder_manager; pub mod utils; -// const INPUT_PATH: &str = "/tank/ephemeral/anime/series/Witch Hunter Robin - 2ndfire/[2ndfire]Witch_Hunter_Robin_-_01[91DCE49A].mkv"; -const INPUT_PATH: &str = "/tank/ephemeral/anime/series/Brave Witches - Eila/Extras/[Eila] Brave Witches - NCOP [BD 1080p][DB44ED0B].mkv"; const OUTPUT_PATH: &str = "/tmp/transotf"; fn av_err2str(error_code: c_int) -> String { @@ -41,14 +42,27 @@ lazy_static! { unsafe { CStr::from_ptr(av_version_info()).to_str().unwrap_or("n/a") }, ) }; + static ref FAVICON: Vec = include_bytes!("../resources/favicon.ico").to_vec(); } -#[derive(Default)] +#[derive(Default, Clone)] struct State { - manager: RwLock, + manager: Arc>, } -async fn create_transcode(req: Request) -> Result { +#[derive(Serialize)] +struct CreateDTO { + id: String, + manifest: String, + _player: String, +} + +fn build_url(req: &Request, url: String) -> String { + let host = req.header("host").and_then(|x| x.get(0)).unwrap().clone(); + format!("http://{}/{}", host, url.trim_start_matches("/")) +} + +async fn create_transcode(req: Request) -> Result { let params = req.query::>()?; let target = params.get(&"target".to_string()); let target = if let Some(target) = target { @@ -82,18 +96,22 @@ async fn create_transcode(req: Request) -> Result { ) })?; - Ok(format!("{}", id)) -} + let id = id.to_string(); + let dto = CreateDTO { + manifest: build_url(&req, format!("/session/{}/manifest.mpd", id)), + _player: build_url(&req, format!("/session/{}/player", id)), + id, + }; -async fn get_init(req: Request) -> Result { - let _manager = req.state().manager.read().await; - // manager.get() + let mut resp = Response::new(200); + resp.set_body(Body::from_json(&dto)?); + resp.insert_header("Content-Type", "application/json"); - Err(HttpError::from_str(StatusCode::NotFound, ":3")) + Ok(resp) } async fn get_instance(req: &Request) -> Result, HttpError> { - let id = req.param::("id")?; + let id = req.param("id")?; let id = Uuid::from_str(&id)?; let manager = req.state().manager.read().await; if let Some(instance) = manager.get(id) { @@ -101,45 +119,159 @@ async fn get_instance(req: &Request) -> Result, H } else { Err(HttpError::from_str( StatusCode::NotFound, - format!("Can't find transcoder with id {}", id), + format!("Can't find session with id {}", id), )) } } -async fn get_manifest(req: Request) -> Result { +#[derive(Template)] +#[template(path = "manifest.xml")] +struct MPDManifest { + id: Uuid, + has_audio: bool, + duration: f64, + is_vlc: bool, + audio_time_base_den: i32, + video_time_base_den: i32, +} + +mod filters { + pub fn iso_duration(secs: &f64) -> ::askama::Result { + let minutes = (secs / 60.0).floor(); + let secs = ((secs % 60.0) * 100.0).floor() / 100.0; + let hours = (minutes / 60.0).floor(); + let minutes = minutes % 60.0; + return Ok(format!("PT{}H{}M{}S", hours, minutes, secs)); + } +} + +async fn get_manifest(req: Request) -> Result { let transcoder_instance = get_instance(&req).await?; - let (duration, segments, init_written) = transcoder_instance - .state(|item| { - ( - item.duration(), - item.segments().clone(), - item.init_written(), - ) - .clone() - }) - .await; + let id = transcoder_instance.id(); + let status = transcoder_instance.status().await; + + let mut resp = Response::new(200); + resp.insert_header("Content-Type", "application/dash+xml"); + + let mpd = MPDManifest { + id, + has_audio: status.audio.is_some(), + duration: status.duration_secs, + is_vlc: req + .header("User-Agent") + .map(|x| x.last().to_string()) + .map_or(false, |x| x.starts_with("VLC")), + audio_time_base_den: status.audio.map_or(0, |audio| audio.time_scale), + video_time_base_den: status.video.time_scale, + }; + + resp.set_body(mpd.render().unwrap()); + + Ok(resp) +} + +async fn get_init(req: Request) -> Result { + let transcoder_instance = get_instance(&req).await?; + let type_ = req.param("type").unwrap(); + let id = transcoder_instance.id(); + + if (type_ != "audio" && type_ != "video") || !transcoder_instance.wait_for_init().await { + return Ok(Response::new(StatusCode::NotFound)); + } + + let mut ok = Response::new(StatusCode::Ok); + ok.insert_header("Content-Type", "video/mp4"); + ok.set_body(Body::from_file(format!("{}/{}/{}-init.mp4", OUTPUT_PATH, id, type_)).await?); + + Ok(ok) +} + +async fn get_segment(req: Request) -> Result { + let transcoder_instance = get_instance(&req).await?; + let type_ = req.param("type").unwrap(); + let segment = req.param("nr").unwrap(); + let id = transcoder_instance.id(); + + if !segment.ends_with(".m4s") + || (type_ != "audio" && type_ != "video") + || !transcoder_instance.wait_for_init().await + { + return Ok(Response::new(StatusCode::NotFound)); + } + + let segment = &segment[0..segment.len() - 4]; + let segment = if let Ok(segment) = u32::from_str(segment) { + segment + } else { + return Ok(Response::new(StatusCode::NotFound)); + }; + + let status = transcoder_instance.status().await; + if (segment as i64 - 5) > status.current_segment as i64 || segment < status.current_segment { + if !status.segments.contains(&segment) { + transcoder_instance.seek(segment).await; + } + } + + if !transcoder_instance.wait_for_segment(segment).await { + return Ok(Response::new(StatusCode::NotFound)); + } + + let mut ok = Response::new(StatusCode::Ok); + ok.insert_header("Content-Type", "video/mp4"); + ok.set_body( + Body::from_file(format!( + "{}/{}/{}-segment-{:0>5}.m4s", + OUTPUT_PATH, id, type_, segment + )) + .await?, + ); + + Ok(ok) +} + +async fn get_player(req: Request) -> Result { + get_instance(&req).await?; + let mut resp = Response::new(StatusCode::Ok); + resp.insert_header("Content-Type", "text/html"); + resp.set_body(include_str!("../resources/player.html")); - Ok(format!("{} {:?} {}", duration, segments, init_written)) + Ok(resp) } -// async fn get_status(req: Request) -> Result { -// let id = req.param::("id")?; -// let id = Uuid::from_str(&id)?; -// let manager = req.state().manager.read().await; -// } +async fn get_favicon(_: Request) -> Result { + let mut resp = Response::new(StatusCode::Ok); + resp.insert_header("Content-Type", "image/x-icon"); + resp.set_body(Vec::deref(&FAVICON)); + + Ok(resp) +} + +async fn get_status(req: Request) -> Result { + let instance = get_instance(&req).await?; + let mut resp = Response::new(StatusCode::Ok); + resp.insert_header("Content-Type", "application/json"); + resp.set_body(Body::from_json(&instance.status().await)?); + + Ok(resp) +} #[async_std::main] async fn main() -> std::io::Result<()> { - println!("{}", HOME_PAGE.clone()); - init(); let mut app = tide::with_state(State::default()); app.at("/").get(|_| async { Ok(HOME_PAGE.clone()) }); + app.at("/favicon.ico").get(get_favicon); app.at("/transcode").get(create_transcode); - // app.at("/session/:id").get(get_status); + app.at("/session/:id/status.json").get(get_status); + app.at("/session/:id/player").get(get_player); app.at("/session/:id/manifest").get(get_manifest); - // app.at("/session/:id/{type}/init.mp4"); - // app.at("/session/:id/{type}/{nr}.m4s"); - app.listen("0:8000").await + app.at("/session/:id/manifest.xml").get(get_manifest); + app.at("/session/:id/manifest.mpd").get(get_manifest); + app.at("/session/:id/:type/init.mp4").get(get_init); + app.at("/session/:id/:type/:nr").get(get_segment); + let listen_fut = app.listen("0:8000"); + println!("Listening on 0:8000"); + listen_fut.await } diff --git a/src/transcoder.rs b/src/transcoder.rs index 633f278..aa6df79 100644 --- a/src/transcoder.rs +++ b/src/transcoder.rs @@ -16,7 +16,7 @@ use ffmpeg_sys_next::AVPictureType::AV_PICTURE_TYPE_I; use ffmpeg_sys_next::AVPixelFormat::AV_PIX_FMT_YUV420P; use ffmpeg_sys_next::{avio_wb32, AVIOContext, AVPixelFormat, AV_TIME_BASE, SWS_BILINEAR}; use num_rational::Ratio; -use std::cmp::min; +use std::cmp::{max, min}; use std::fs::{DirBuilder, File}; use std::io::Write; use std::ops::Mul; @@ -31,13 +31,17 @@ pub struct AudioTranscoder { format: Format, output_path: String, resampler: Resampler, - segment: u32, + segment: Option, last_pts: i64, current_pts: i64, seconds_per_segment: u32, + segment_target: Option, + header_written: bool, + last_written_segment: Option, + latest_written_segment: Option, } -const SECONDS_PER_SEGMENT: u32 = 5; +pub const SECONDS_PER_SEGMENT: u32 = 5; impl AudioTranscoder { fn process_packet(&mut self, packet: Packet) -> Result<(), String> { @@ -45,10 +49,22 @@ impl AudioTranscoder { .send_packet(&packet) .map_err(|err| format!("Failed sending audio packet: {}", err))?; while let Some(frame) = self.decoder.read_frame()? { + if let Some(target) = self.segment_target { + let segment = (self + .input_stream + .time_base() + .mul(frame.pts() as i32) + .to_integer() + / self.seconds_per_segment as i32) as u32; + if (target as i64 - 1) > (segment as i64) { + continue; + } + } + let resampled = self.resampler.convert(&frame)?; let resampled_pts = resampled.pts(); self.frame_buffer.insert_frame(resampled); - let mut offset: f64 = 0f64; + let mut offset: f64 = 0.0; while let Some(drain_resampled) = self.resampler.drain()? { offset += (drain_resampled.nb_samples() as f64 / self.encoder.sample_rate() as f64) * self.input_stream.time_base().den() as f64; @@ -63,12 +79,25 @@ impl AudioTranscoder { } #[inline] - fn input_stream(&self) -> &Stream { + pub fn input_stream(&self) -> &Stream { &self.input_stream } + #[inline] + pub fn output_stream(&self) -> &Stream { + &self.output_stream + } + + pub fn encoder(&self) -> &Encoder { + &self.encoder + } + + pub fn decoder(&self) -> &Decoder { + &self.decoder + } + fn start_segment(&self, force: bool) { - if self.segment == 0 && !force { + if self.segment == Some(0) && !force { return; } @@ -97,8 +126,16 @@ impl AudioTranscoder { } fn write_segment(&mut self) -> Result<(), String> { - if self.segment == 0 { + if self.segment == Some(0) { self.write_header()?; + self.header_written = true; + } + + if !self.header_written { + self.format.avio_inner_mut().unwrap().buffer(); + self.start_segment(true); + self.format.write_packet_null()?; + self.header_written = true; } if let Some(avio) = self.format.avio.as_mut() { @@ -107,32 +144,82 @@ impl AudioTranscoder { let mut segment = self.format.avio_inner_mut().unwrap().buffer(); - File::create(format!( - "{}/audio-segment-{:0>5}.m4s", - self.output_path, self.segment - )) - .unwrap() - .write_all(&mut segment) - .map_err(|_| format!("Failed to write audio segment {}", self.segment))?; + if self.segment_target.unwrap_or(self.segment.unwrap()) == self.segment.unwrap() { + self.segment_target = None; + File::create(format!( + "{}/audio-segment-{:0>5}.m4s", + self.output_path, + self.segment.unwrap() + )) + .unwrap() + .write_all(&mut segment) + .map_err(|_| format!("Failed to write audio segment {}", self.segment.unwrap()))?; + println!("Wrote segment (audio) {}", self.segment.unwrap()); + self.last_written_segment = self.segment; + self.latest_written_segment = + max(self.latest_written_segment, Some(self.segment.unwrap())); + } else { + println!( + "Won't write segment (audio) {} (searching for {})", + self.segment.unwrap(), + self.segment_target.unwrap() + ) + } self.start_segment(false); - Ok(()) } fn encode(&mut self) -> Result<(), String> { while let Some(frame) = self.frame_buffer.pop_first() { - let pts_passed = frame.pts() - self.last_pts; - if pts_passed <= 0 && self.last_pts != 0 { - println!("WARN: new frame out of order"); + if self.last_pts > frame.pts() { + println!("WARN: out of order frame"); + self.last_pts = frame.pts(); } - if (pts_passed + self.current_pts) - > (self.seconds_per_segment as i32 * self.input_stream.time_base().den()) as i64 + if self.last_pts == 0 { + self.last_pts = frame.pts(); + } + + self.current_pts = frame.pts() + % (self.input_stream.time_base().den() as u32 * self.seconds_per_segment) as i64; + self.segment = Some( + (frame.pts() as f64 / self.input_stream.time_base().den() as f64).floor() as u32 + / self.seconds_per_segment, + ); + + if self.current_pts == 0 && Some(0) < self.segment { + self.segment = Some(self.segment.unwrap() - 1) + } + + let (should_skip, peek) = if let Some(peek) = self.frame_buffer.first_key() { + ( + (self.current_pts + (peek - frame.pts())) + < (self.seconds_per_segment * self.input_stream.time_base().den() as u32) + as i64, + peek, + ) + } else { + (false, frame.pts()) + }; + + let pts_passed = peek - frame.pts(); + + if self.segment == Some(2) { + println!( + ">>>>>> {} {} {} {:?} {}", + self.current_pts, self.last_pts, pts_passed, should_skip, peek + ); + } + + if (!should_skip || self.current_pts == 0) + && ((pts_passed + self.current_pts) + > (self.seconds_per_segment * self.input_stream.time_base().den() as u32) + as i64 + || (self.current_pts == 0 && Some(0) < self.segment)) { self.format.write_packet_null()?; self.write_segment()?; - self.segment += 1; self.current_pts = (pts_passed + self.current_pts) % self.input_stream.time_base().den() as i64; } else { @@ -157,6 +244,27 @@ impl AudioTranscoder { Ok(()) } + + fn static_create_output(input: &Format<()>) -> Result<(Format, Stream), String> { + let audio_avio = AVIO::writer(Buffer::default()); + let format = Format::output_avio(audio_avio, "mp4")?; + let output_stream = format.new_stream("aac")?; + format.set_flags(input.flags()); + + Ok((format, output_stream)) + } + + fn create_output(&mut self, input: &Format<()>) -> Result<(), String> { + let (format, stream) = Self::static_create_output(input)?; + self.output_stream = stream; + self.format = format; + + Ok(()) + } + + fn open_output(&self) -> Result<(), String> { + Transcoder::static_open_output(&self.format, None) + } } pub struct Transcoder { @@ -172,13 +280,17 @@ pub struct Transcoder { frame_scaler: Scaler, last_pts: i64, current_pts: i64, - video_segment: u32, + highest_pts: i64, + video_segment: Option, extra_data: Option>, audio: Option, segment_target: Option, input_video_index: Option, input_audio_index: Option, seconds_per_segment: u32, + header_written: bool, + last_written_segment: Option, + latest_written_segment: Option, } impl Transcoder { @@ -192,12 +304,16 @@ impl Transcoder { let output_path = output_path.to_string(); let input_video = input - .stream(AVMEDIA_TYPE_VIDEO, video_index, None) + .stream(Some(AVMEDIA_TYPE_VIDEO), video_index, None) .map_err(|err| format!("Failed to find video stream: {}", err))? .ok_or("Failed to find video stream".to_string())?; let input_audio = input - .stream(AVMEDIA_TYPE_AUDIO, audio_index, Some(input_video.index())) + .stream( + Some(AVMEDIA_TYPE_AUDIO), + audio_index, + Some(input_video.index()), + ) .map_err(|err| format!("Failed to find audio stream: {}", err))?; if audio_index.is_some() && input_audio.is_none() { return Err("Failed to find audio stream".to_string()); @@ -205,23 +321,9 @@ impl Transcoder { let input_frame_rate = input_video.avg_frame_rate(&input).unwrap().to_num(); - let mut options = Dictionary::new(); - options.set("movflags", "+dash+delay_moov+skip_trailer+frag_custom"); - - let video_avio = AVIO::writer(Buffer::default()); - let video_output = Format::output_avio(video_avio, "mp4")?; - let output_video = video_output.new_stream("h264")?; - output_video.params().copy_from(&input_video.params())?; - output_video.set_sample_aspect_ratio(input_video.sample_aspect_ratio()); - video_output.set_flags(input.flags()); - + let (video_output, output_video) = Self::create_streams(&input, &input_video)?; let audio = if let Some(input_stream) = input_audio { - let audio_avio = AVIO::writer(Buffer::default()); - let format = Format::output_avio(audio_avio, "mp4")?; - let output_stream = format.new_stream("aac")?; - - format.set_flags(input.flags()); - + let (format, output_stream) = AudioTranscoder::static_create_output(&input)?; let decoder = input_stream.decoder(None).ok_or(format!( "Couldn't find encoder for input audio with codec: {:?}", input_stream.codec() @@ -251,9 +353,7 @@ impl Transcoder { encoder.configure(&output_stream)?; let resampler = Resampler::from_coder(&decoder, &encoder); - let mut audio_options = Dictionary::new(); - audio_options.copy_from(&mut options)?; - format.init_output(audio_options)?; + Transcoder::static_open_output(&format, None)?; Some(AudioTranscoder { frame_buffer: SortedFrameBuffer::new(), @@ -265,9 +365,13 @@ impl Transcoder { output_path: output_path.to_string(), current_pts: 0, last_pts: 0, - segment: 0, + segment: None, resampler, seconds_per_segment: SECONDS_PER_SEGMENT, + segment_target: None, + header_written: false, + latest_written_segment: None, + last_written_segment: None, }) } else { None @@ -288,18 +392,13 @@ impl Transcoder { encoder.set_height(video_decoder.height()); encoder.set_width(video_decoder.width()); encoder.set_time_base(input_frame_rate.invert()); - output_video.set_time_base(encoder.time_base()); encoder.open()?; encoder.configure(&output_video)?; Ok(()) })?; - let param = output_video.params(); - param.set_height(video_decoder.height()); - param.set_width(video_decoder.width()); - param.set_pixel_format(AV_PIX_FMT_YUV420P); - video_output.init_output(options)?; + Self::static_open_output(&video_output, Some((&input_video, &video_decoder)))?; let frame_scaler = Scaler::from_coder(&video_decoder, &video_encoder, SWS_BILINEAR); let video_frame_buffer = SortedFrameBuffer::new(); @@ -320,15 +419,121 @@ impl Transcoder { video_frame_buffer, last_pts: 0, current_pts: 0, - video_segment: 0, + video_segment: None, extra_data: None, input_audio_index: None, seconds_per_segment: SECONDS_PER_SEGMENT, + header_written: false, + latest_written_segment: None, + last_written_segment: None, + highest_pts: 0, }) } - pub fn seek(&self, segment: u32, stream: Option<&Stream>) -> Result<(), String> { - self.input.seek(segment * self.seconds_per_segment, stream) + fn create_output(&mut self) -> Result<(), String> { + let (video_output, output_video) = Self::create_streams(&self.input, &self.input_video)?; + self.video_output = video_output; + self.output_video = output_video; + + Ok(()) + } + + fn create_streams( + input: &Format<()>, + input_video: &Stream, + ) -> Result<(Format, Stream), String> { + let video_avio = AVIO::writer(Buffer::default()); + let video_output = Format::output_avio(video_avio, "mp4")?; + let output_video = video_output.new_stream("h264")?; + output_video.params().copy_from(&input_video.params())?; + output_video.set_sample_aspect_ratio(input_video.sample_aspect_ratio()); + video_output.set_flags(input.flags()); + + Ok((video_output, output_video)) + } + + fn open_output(&self) -> Result<(), String> { + Self::static_open_output( + &self.video_output, + Some((&self.output_video, &self.video_decoder)), + ) + } + + fn static_open_output( + output: &Format, + video: Option<(&Stream, &Decoder)>, + ) -> Result<(), String> { + let mut options = Dictionary::new(); + options.set("movflags", "+dash+delay_moov+skip_trailer+frag_custom"); + + if let Some((video, video_decoder)) = video { + let param = video.params(); + param.set_height(video_decoder.height()); + param.set_width(video_decoder.width()); + param.set_pixel_format(AV_PIX_FMT_YUV420P); + } + output.init_output(options) + } + + pub fn video_encoder(&self) -> &Encoder { + &self.video_encoder + } + + pub fn video_decoder(&self) -> &Decoder { + &self.video_decoder + } + + pub fn reset_output(&mut self) -> Result<(), String> { + let time_base = self.output_video.time_base(); + self.create_output()?; + self.output_video + .set_time_base(self.video_encoder.time_base()); + self.video_encoder.configure(&self.output_video)?; + self.open_output()?; + self.video_encoder.flush(); + self.output_video.set_time_base(time_base); + self.video_segment = None; + self.header_written = false; + let mut options = Dictionary::new(); + options.set("movflags", "+dash+delay_moov+skip_trailer+frag_custom"); + self.video_output.write_header(Some(options)).unwrap(); + + if let Some(audio) = self.audio.as_mut() { + let time_base = audio.output_stream.time_base(); + audio.create_output(&self.input)?; + audio.output_stream.set_time_base(audio.encoder.time_base()); + audio.encoder.configure(&audio.output_stream)?; + audio.open_output()?; + audio.encoder.flush(); + audio.output_stream.set_time_base(time_base); + audio.segment = None; + audio.header_written = false; + let mut options = Dictionary::new(); + options.set("movflags", "+dash+delay_moov+skip_trailer+frag_custom"); + audio.format.write_header(Some(options)).unwrap(); + audio.last_pts = 0; + } + + Ok(()) + } + + pub fn seek(&mut self, segment: u32, stream_index: Option) -> Result<(), String> { + self.input.seek( + segment * self.seconds_per_segment, + stream_index, + segment < self.last_written_segment().unwrap_or(0), + )?; + self.reset_output()?; + self.video_frame_buffer.clear(); + self.segment_target = Some(segment); + self.video_segment = None; + if let Some(audio) = self.audio.as_mut() { + audio.frame_buffer.clear(); + audio.segment_target = Some(segment); + audio.segment = None; + } + + Ok(()) } pub fn open(&mut self) -> Result<(), String> { @@ -336,37 +541,56 @@ impl Transcoder { .recursive(true) .create(self.output_path.to_string()) .map_err(|_| "Failed to create target directory".to_string())?; - - self.video_output.write_header(None).unwrap(); + let mut options = Dictionary::new(); + options.set("movflags", "+dash+delay_moov+skip_trailer+frag_custom"); + self.video_output.write_header(Some(options)).unwrap(); self.input_video_index = Some(self.input_video.index()); self.input_audio_index = self.audio.as_ref().map(|ia| ia.input_stream.index()); Ok(()) } - pub fn duration(&self) -> i64 { - self.input.duration() + pub fn last_frame_secs(&self) -> f64 { + self.last_pts as f64 / self.input_video.time_base().den() as f64 + } + + pub fn latest_frame_secs(&self) -> f64 { + self.highest_pts as f64 / self.input_video.time_base().den() as f64 } pub fn duration_secs(&self) -> f64 { self.input.duration() as f64 / AV_TIME_BASE as f64 } + pub fn has_audio(&self) -> bool { + self.audio.is_some() + } + pub fn transcode(&mut self) -> Result { - Ok(if let Some(packet) = self.input.next_packet() { + if let Some(packet) = self.input.next_packet() { if self.input_video_index == Some(packet.stream()) { self.video_process_packet(packet)?; } else if self.input_audio_index == Some(packet.stream()) { - // Safe assumption if let Some(ref mut audio) = &mut self.audio { audio.process_packet(packet)?; } } - true - } else { - false - }) + return Ok(true); + } + + self.video_frame_buffer.close(); + self.encode_video()?; + if let Some(audio) = self.audio.as_mut() { + audio.frame_buffer.close(); + audio.encode()?; + } + + Ok(false) + } + + pub fn avg_frame_rate(&self) -> Option { + self.video_stream().avg_frame_rate(&self.input) } #[inline] @@ -374,6 +598,11 @@ impl Transcoder { &self.input_video } + #[inline] + pub fn audio(&self) -> Option<&AudioTranscoder> { + self.audio.as_ref() + } + #[inline] pub fn audio_stream(&self) -> Option<&Stream> { if let Some(ref audio) = self.audio { @@ -383,10 +612,36 @@ impl Transcoder { } } + pub fn seeking(&self) -> bool { + self.segment_target.is_some() + || self + .audio + .as_ref() + .map_or(false, |audio| audio.segment_target.is_some()) + } + + pub fn last_written_audio_segment(&self) -> Option { + self.audio.as_ref().and_then(|x| x.last_written_segment) + } + + pub fn last_written_segment(&self) -> Option { + self.last_written_segment + } + + pub fn latest_written_segment(&self) -> Option { + if let Some(audio) = self.audio.as_ref() { + min(self.latest_written_segment, audio.latest_written_segment) + } else { + self.latest_written_segment + } + } + pub fn segment(&self) -> u32 { min( - self.video_segment, - self.audio.as_ref().map_or(u32::MAX, |audio| audio.segment), + self.video_segment.unwrap_or(0), + self.audio + .as_ref() + .map_or(u32::MAX, |audio| audio.segment.unwrap_or(u32::MAX)), ) } @@ -395,6 +650,12 @@ impl Transcoder { self.video_output.write_trailer()?; self.video_write_segment()?; + if let Some(audio) = self.audio.as_mut() { + audio.encode()?; + audio.format.write_trailer()?; + audio.write_segment()?; + } + Ok(()) } @@ -404,12 +665,11 @@ impl Transcoder { let segment: u32 = (self .input_video .time_base() - .to_num() .mul(packet.pts() as i32) .to_integer() / self.seconds_per_segment as i32) as u32; if let Some(target) = self.segment_target { - if target - 1 < segment { + if (target as i64 - 1) > (segment as i64) { continue; } } @@ -441,8 +701,16 @@ impl Transcoder { } fn video_write_segment(&mut self) -> Result<(), String> { - if self.video_segment == 0 { + if self.video_segment == Some(0) { self.video_write_header()?; + self.header_written = true; + } + + if !self.header_written { + self.video_output.avio_inner_mut().unwrap().buffer(); + self.start_segment(true); + self.video_output.write_packet_null()?; + self.header_written = true; } if let Some(avio) = self.video_output.avio.as_mut() { @@ -450,15 +718,48 @@ impl Transcoder { } let segment = self.video_output.avio_inner_mut().unwrap().buffer(); - let mut segment = annex_b_to_avc(segment, 4)?; - - File::create(format!( - "{}/video-segment-{:0>5}.m4s", - self.output_path, self.video_segment - )) - .unwrap() - .write_all(&mut segment) - .map_err(|_| format!("Failed to write video segment {}", self.video_segment))?; + if self.segment_target.unwrap_or(self.video_segment.unwrap()) == self.video_segment.unwrap() + { + self.segment_target = None; + let segment_res = annex_b_to_avc(segment, 4); + if let Err(_) = segment_res { + println!("oh"); + } + let mut segment = segment_res?; + + File::create(format!( + "{}/video-segment-{:0>5}.m4s", + self.output_path, + self.video_segment.unwrap() + )) + .unwrap() + .write_all(&mut segment) + .map_err(|_| { + format!( + "Failed to write video segment {}", + self.video_segment.unwrap() + ) + })?; + self.last_written_segment = self.video_segment; + self.latest_written_segment = max( + self.latest_written_segment, + Some(self.video_segment.unwrap()), + ); + println!( + "Wrote segment (video) {} ({} -> {} / coder: {} {})", + self.video_segment.unwrap(), + self.input_video.time_base(), + self.output_video.time_base(), + self.video_decoder.time_base(), + self.video_encoder.time_base() + ); + } else { + println!( + "Won't write segment (video) {} (searching for {})", + self.video_segment.unwrap(), + self.segment_target.unwrap() + ) + } self.start_segment(false); self.video_encoder.flush(); Ok(()) @@ -466,21 +767,42 @@ impl Transcoder { fn encode_video(&mut self) -> Result<(), String> { while let Some(frame) = self.video_frame_buffer.pop_first() { + // if self.video_segment == None || self.last_pts > frame.pts() { + self.last_pts = frame.pts() + - (self + .avg_frame_rate() + .unwrap() + .invert() + .to_num() + .mul(self.input_video.time_base().den() as i32)) + .as_f64() as i64; + self.current_pts = frame.pts() + % (self.input_video.time_base().den() as u32 * self.seconds_per_segment) as i64; + self.video_segment = Some( + (frame.pts() as f64 / self.input_video.time_base().den() as f64).floor() as u32 + / self.seconds_per_segment, + ); + + if self.current_pts == 0 && Some(0) < self.video_segment { + self.video_segment = Some(self.video_segment.unwrap() - 1) + } + let pts_passed = frame.pts() - self.last_pts; if (pts_passed + self.current_pts) - > (self.seconds_per_segment * self.input_frame_rate.den() as u32) as i64 + > (self.seconds_per_segment * self.input_video.time_base().den() as u32) as i64 + || (self.current_pts == 0 && Some(0) < self.video_segment) { self.video_output.write_packet_null()?; self.video_write_segment()?; - self.video_segment += 1; self.current_pts = - (pts_passed + self.current_pts) % self.input_frame_rate.den() as i64; + (pts_passed + self.current_pts) % self.input_video.time_base().den() as i64; frame.set_pict_type(AV_PICTURE_TYPE_I); } else { self.current_pts += pts_passed } self.last_pts = frame.pts(); + self.highest_pts = max(self.highest_pts, self.last_pts); self.video_encoder.send_video_frame(&frame)?; while let Some(new_packet) = self.video_encoder.read_packet()? { @@ -525,8 +847,16 @@ impl Transcoder { Ok(()) } + pub fn video_stream_output(&self) -> &Stream { + &self.output_video + } + + pub fn audio_stream_output(&self) -> Option<&Stream> { + self.audio.as_ref().map(|audio| &audio.output_stream) + } + fn start_segment(&self, force: bool) { - if self.video_segment == 0 && !force { + if self.video_segment == Some(0) && !force { return; } diff --git a/src/transcoder_manager.rs b/src/transcoder_manager.rs index f0905b6..0b27607 100644 --- a/src/transcoder_manager.rs +++ b/src/transcoder_manager.rs @@ -1,38 +1,188 @@ -use crate::transcoder::Transcoder; -use async_std::sync::{Arc, Receiver, RecvError, RwLock, RwLockReadGuard, Sender, TryRecvError}; +use crate::av::xcoder::XCoder; +use crate::av::Rational; +use crate::transcoder::{Transcoder, SECONDS_PER_SEGMENT}; +use async_std::channel::{bounded, Receiver, RecvError, SendError, Sender, TryRecvError}; +use async_std::sync::{Arc, RwLock, RwLockReadGuard}; use async_std::task; +use futures::channel::oneshot::{ + channel as one_shot, Receiver as OneShotReceiver, Sender as OneShotSender, +}; +use serde::Serialize; +use std::cmp::min; use std::collections::{HashMap, HashSet}; use std::option::Option::Some; use std::thread::Builder; use std::thread::JoinHandle; use uuid::Uuid; +#[derive(Debug, Default)] +struct OneShotSet(Vec>); + +impl OneShotSet { + fn add(&mut self) -> OneShotReceiver<()> { + let (s, r) = one_shot::<()>(); + self.0.push(s); + + r + } + + fn trigger(&mut self) { + while let Some(sender) = self.0.pop() { + sender.send(()).unwrap() + } + } + + fn new() -> OneShotSet { + OneShotSet(vec![]) + } +} + +#[derive(Debug, Default)] +pub struct TranscoderEvents { + init_queue: OneShotSet, + segment_queue: HashMap, +} + +impl TranscoderEvents { + pub fn new() -> TranscoderEvents { + Default::default() + } +} + #[derive(Debug)] pub struct TranscoderInstance { id: Uuid, channel: Channel, state: RwLock, command: TranscoderCommand, + events: RwLock, + status: RwLock, } impl TranscoderInstance { pub async fn state(&self, block: fn(RwLockReadGuard) -> T) -> T { block(self.state.read().await) } + + pub fn id(&self) -> Uuid { + self.id + } + + pub async fn seek(&self, segment: u32) { + self.channel.send(Message::Seek(segment)).await.unwrap() + } + + pub async fn wait_for_segment(&self, segment: u32) -> bool { + { + let state = self.state.read().await; + if state.info.segments() < segment { + return false; + } + + if state.segments.contains(&segment) { + return true; + } + + if state.state == TranscoderState::Finished { + return false; + } + } + + println!("Waiting in segment queue for segment {}", segment); + let r = { + self.events + .write() + .await + .segment_queue + .entry(segment) + .or_insert_with(|| OneShotSet::new()) + .add() + }; + + r.await.is_ok() + } + + pub async fn wait_for_init(&self) -> bool { + if self.state.read().await.init_written { + return true; + } + + let r = { self.events.write().await.init_queue.add() }; + + r.await.is_ok() + } + + pub async fn status(&self) -> TranscoderStatus { + self.status.read().await.clone() + } +} + +#[derive(Serialize, Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq)] +pub enum TranscoderState { + None, + Seeking, + Transcoding, + Failed, + Stopped, + Finished, +} + +impl Default for TranscoderState { + fn default() -> Self { + TranscoderState::None + } +} + +#[derive(Serialize, Debug, Clone, Default)] +pub struct VideoInput { + pub codec: String, + pub encoder: String, + pub decoder: String, + pub frame_rate_rat: Option<[u32; 2]>, + pub frame_rate: Option, + pub width: u32, + pub height: u32, + pub time_scale: i32, +} + +#[derive(Serialize, Debug, Clone, Default)] +pub struct AudioInput { + pub codec: String, + pub encoder: String, + pub decoder: String, + pub channels: i32, + pub channel_layout: String, + pub sample_rate: i32, + pub time_scale: i32, +} + +#[derive(Serialize, Debug, Clone, Default)] +pub struct TranscoderStatus { + pub state: TranscoderState, + pub failure_reason: Option, + pub segments: Vec, + pub init_written: bool, + pub duration_secs: f64, + pub current_segment: u32, + pub segment_count: u32, + pub video: VideoInput, + pub audio: Option, } #[derive(Debug, Default)] pub struct TranscoderInstanceState { thread: Option>, - duration_secs: f64, + info: TranscoderInfo, segments: HashSet, init_written: bool, + state: TranscoderState, + failure_reason: Option, } impl TranscoderInstanceState { #[inline] - pub fn duration(&self) -> f64 { - self.duration_secs + pub fn info(&self) -> &TranscoderInfo { + &self.info } #[inline] @@ -58,11 +208,11 @@ pub struct Channel { } impl Channel { - async fn send(&self, msg: T) { + async fn send(&self, msg: T) -> Result<(), SendError> { self.sender.send(msg).await } - fn send_blocking(&self, msg: T) { + fn send_blocking(&self, msg: T) -> Result<(), SendError> { task::block_on(self.sender.send(msg)) } @@ -80,8 +230,8 @@ impl Channel { } fn new_channel() -> (Channel, Channel) { - let (sender_a, receiver_a) = async_std::sync::channel(25); - let (sender_b, receiver_b) = async_std::sync::channel(25); + let (sender_a, receiver_a) = bounded(25); + let (sender_b, receiver_b) = bounded(25); ( Channel { @@ -103,19 +253,34 @@ pub struct TranscoderCommand { video: Option, } +#[derive(Debug, Clone, Default)] +pub struct TranscoderInfo { + pub duration_secs: f64, + pub audio: Option, + pub video: VideoInput, +} + +impl TranscoderInfo { + fn segments(&self) -> u32 { + (self.duration_secs / SECONDS_PER_SEGMENT as f64).ceil() as u32 + } +} + #[derive(Debug)] pub enum Message { - Info { duration_secs: f64 }, + Info(TranscoderInfo), SegmentReady(u32), Seek(u32), + Seeking, Failure(String), Stop, - Finished, + Stopped, + Finished(f64, u32), } fn transcoder_thread_main(command: TranscoderCommand, channel: Channel) { if let Err(err) = transcoder_thread(command, &channel) { - channel.send_blocking(Message::Failure(err)); + channel.send_blocking(Message::Failure(err)).unwrap(); return; } } @@ -131,43 +296,124 @@ fn transcoder_thread(command: TranscoderCommand, channel: &Channel) -> let mut transcoder = match transcoder { Ok(t) => t, Err(e) => { - channel.send_blocking(Message::Failure(e)); + channel.send_blocking(Message::Failure(e)).unwrap(); return Ok(()); } }; + let mut segments = HashSet::new(); + let mut video_segments = HashSet::new(); + let mut video_last_segment = None; + let mut audio_segments = HashSet::new(); + let mut audio_last_segment = None; transcoder.open()?; - channel.send_blocking(Message::Info { - duration_secs: transcoder.duration_secs(), - }); + channel + .send_blocking(Message::Info(TranscoderInfo { + duration_secs: transcoder.duration_secs(), + audio: transcoder.audio().map(|audio| AudioInput { + codec: audio.input_stream().codec_name(), + decoder: audio.decoder().name(), + encoder: audio.encoder().name(), + channels: audio.decoder().channels(), + channel_layout: audio.decoder().channel_layout_name(), + sample_rate: audio.decoder().sample_rate(), + time_scale: audio.output_stream().time_base().den(), + }), + video: VideoInput { + codec: transcoder.video_stream().codec_name(), + encoder: transcoder.video_encoder().name(), + decoder: transcoder.video_decoder().name(), + frame_rate_rat: transcoder + .avg_frame_rate() + .map(|x| [x.den() as u32, x.num() as u32]), + frame_rate: transcoder.avg_frame_rate().map(|x| x.as_f64()), + width: transcoder.video_decoder().width() as u32, + height: transcoder.video_decoder().height() as u32, + time_scale: transcoder.video_stream_output().time_base().den(), + }, + })) + .unwrap(); + + let mut completed = false; + let has_audio = transcoder.has_audio(); + + while !completed { + if transcoder.transcode()? { + while let Ok(msg) = channel.try_recv() { + match msg { + Message::Seek(segment) => { + channel.send_blocking(Message::Seeking).unwrap(); + let stream = Some(transcoder.video_stream().index()); + transcoder.seek(segment, stream)?; + } + Message::Stop => { + transcoder.stop(); + channel.send_blocking(Message::Stopped).unwrap(); + return Ok(()); + } + + _ => {} + }; + } - let mut last_segment = transcoder.segment(); - while transcoder.transcode()? { - while let Ok(msg) = channel.try_recv() { - match msg { - Message::Seek(segment) => { - transcoder.seek(segment, Some(transcoder.video_stream()))?; + if video_last_segment != transcoder.last_written_segment() { + if let Some(segment) = transcoder.last_written_segment() { + video_segments.insert(segment); + if !has_audio || audio_segments.contains(&segment) { + channel + .send_blocking(Message::SegmentReady(segment)) + .unwrap(); + segments.insert(segment); + } } - Message::Stop => { - transcoder.stop(); - return Ok(()); + + video_last_segment = transcoder.last_written_segment(); + } + + if audio_last_segment != transcoder.last_written_audio_segment() { + if let Some(segment) = transcoder.last_written_audio_segment() { + audio_segments.insert(segment); + if video_segments.contains(&segment) { + channel + .send_blocking(Message::SegmentReady(segment)) + .unwrap(); + segments.insert(segment); + } } - _ => {} - }; - } + audio_last_segment = transcoder.last_written_audio_segment(); + } + } else { + println!("EOF, seeking to missed parts"); + let mut si: u32 = 0; + while si <= transcoder.latest_written_segment().unwrap() as u32 { + if segments.contains(&si) { + si += 1; + continue; + } - if last_segment < transcoder.segment() { - channel.send_blocking(Message::SegmentReady(last_segment)); - last_segment = transcoder.segment(); + println!("Seeking to segment {}", si); + transcoder.seek(si, Some(transcoder.video_stream().index()))?; + break; + } + + if si > transcoder.latest_written_segment().unwrap() { + completed = true; + } } } transcoder.finish()?; - channel.send_blocking(Message::SegmentReady(transcoder.segment())); + channel + .send_blocking(Message::SegmentReady(transcoder.segment())) + .unwrap(); + let duration = transcoder.latest_frame_secs(); + let segment_count = transcoder.segment(); transcoder.stop(); - channel.send_blocking(Message::Finished); + channel + .send_blocking(Message::Finished(duration, segment_count)) + .unwrap(); Ok(()) } @@ -197,13 +443,14 @@ impl TranscoderManager { let instance = TranscoderInstance { id: uuid, command, - state: RwLock::new(TranscoderInstanceState { - thread: Some(thread), - init_written: false, - segments: HashSet::new(), - duration_secs: 0.0, + state: RwLock::new({ + let mut it = TranscoderInstanceState::default(); + it.thread = Some(thread); + it }), channel: own_channel, + events: RwLock::new(TranscoderEvents::new()), + status: Default::default(), }; let instance = Arc::new(instance); @@ -213,34 +460,102 @@ impl TranscoderManager { loop { let fut = instance.channel.recv(); if let Ok(x) = fut.await { + println!("[{}] {:?}", uuid, &x); match x { - Message::Finished => { - let mut state = instance.state.write().await; - if let Some(join_handle) = std::mem::replace(&mut state.thread, None) { - join_handle.join().unwrap(); + Message::Finished(duration, segment_count) => { + { + let mut status = instance.status.write().await; + status.state = TranscoderState::Finished; + status.segment_count = segment_count; + status.duration_secs = duration; + } + + { + let mut state = instance.state.write().await; + if let Some(join_handle) = + std::mem::replace(&mut state.thread, None) + { + join_handle.join().unwrap(); + } } break; } - Message::Info { duration_secs } => { - let mut state = instance.state.write().await; - state.duration_secs = duration_secs + Message::Stopped => { + let mut status = instance.status.write().await; + status.state = TranscoderState::Stopped + } + + Message::Failure(error) => { + let mut status = instance.status.write().await; + status.state = TranscoderState::Failed; + status.failure_reason = Some(error); + } + + Message::Info(info) => { + { + let mut state = instance.state.write().await; + state.info = info.clone() + } + + { + let mut status = instance.status.write().await; + status.audio = info.audio; + status.video = info.video; + status.segment_count = + (info.duration_secs / SECONDS_PER_SEGMENT as f64).ceil() as u32; + status.duration_secs = info.duration_secs + } + } + + Message::Seeking => { + let mut status = instance.status.write().await; + status.state = TranscoderState::Seeking } Message::SegmentReady(segment) => { let mut state = instance.state.write().await; if segment == 0 { - state.init_written = true + state.init_written = true; + instance.events.write().await.init_queue.trigger() } - state.segments.insert(segment); + let current_segment = min(segment + 1, state.info.segments() - 1); + + { + let mut status = instance.status.write().await; + status.init_written = true; + status.current_segment = current_segment; + status.state = TranscoderState::Transcoding; + + if state.segments.insert(segment) { + status.segments.push(segment); + } + } + + instance + .events + .write() + .await + .segment_queue + .get_mut(&segment) + .map(|x| x.trigger()); + + let mut skip_ahead = 1 + segment; + while state.info.segments() > skip_ahead + && state.segments.contains(&skip_ahead) + { + skip_ahead += 1; + } + + if skip_ahead > (segment + 5) { + instance.seek(skip_ahead).await; + } } _ => {} } - - println!("> {:?}", x); } else { return; } diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 680ef7c..5bfbb29 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -87,6 +87,12 @@ impl SortedBuffer { self.open = false; } + pub fn clear(&mut self) { + self.sorted_keys.clear(); + self.items.clear(); + self.lowest_value = None; + } + pub fn first_key(&mut self) -> Option { self.sorted_keys.first().copied() } diff --git a/templates/manifest.xml b/templates/manifest.xml new file mode 100644 index 0000000..8b6b27b --- /dev/null +++ b/templates/manifest.xml @@ -0,0 +1,34 @@ + + + + /session/{{ id }}/ + + + video/ + + + + +{% if has_audio %} + + audio/ + + + + +{% endif %} + + \ No newline at end of file diff --git a/test/index.html b/test/index.html index 69ac45b..e69de29 100644 --- a/test/index.html +++ b/test/index.html @@ -1,66 +0,0 @@ - - - - - DASH Test - - - - - - - - - - \ No newline at end of file