From 280939df755af6112efafa19663091bab27ef402 Mon Sep 17 00:00:00 2001 From: Prateek Sunal Date: Tue, 12 Sep 2023 21:00:52 +0530 Subject: [PATCH 01/27] [FIX] Windows CI (#1568) * fix: undef before * chore: bump rust packages * chore: update vcpkg --- .github/workflows/build_windows.yml | 8 +- src/lib_ccx/ccx_common_platform.h | 1 + src/rust/Cargo.lock | 400 ++++++++++++++++------------ src/rust/Cargo.toml | 2 +- 4 files changed, 229 insertions(+), 182 deletions(-) diff --git a/.github/workflows/build_windows.yml b/.github/workflows/build_windows.yml index f3877c027..37c793a92 100644 --- a/.github/workflows/build_windows.yml +++ b/.github/workflows/build_windows.yml @@ -40,8 +40,8 @@ jobs: id: vcpkg uses: friendlyanon/setup-vcpkg@v1 with: - committish: "2023.06.20" - cache-version: "2" + committish: "2023.08.09" + cache-version: "3" ignore-reserve-cache-error: true - name: Install dependencies run: cd vcpkg && vcpkg integrate install && vcpkg install leptonica tesseract ffmpeg --triplet x64-windows-static @@ -76,8 +76,8 @@ jobs: id: vcpkg uses: friendlyanon/setup-vcpkg@v1 with: - committish: "2023.06.20" - cache-version: "2" + committish: "2023.08.09" + cache-version: "3" ignore-reserve-cache-error: true - name: Install dependencies run: cd vcpkg && vcpkg integrate install && vcpkg install leptonica tesseract ffmpeg --triplet x64-windows-static diff --git a/src/lib_ccx/ccx_common_platform.h b/src/lib_ccx/ccx_common_platform.h index 3702696c3..84eae9751 100644 --- a/src/lib_ccx/ccx_common_platform.h +++ b/src/lib_ccx/ccx_common_platform.h @@ -23,6 +23,7 @@ #define STDOUT_FILENO 1 #define STDERR_FILENO 2 #include "inttypes.h" + #undef UINT64_MAX #define UINT64_MAX _UI64_MAX typedef int socklen_t; typedef int ssize_t; diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 89013e51f..ce4977a95 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -4,22 +4,13 @@ version = 3 [[package]] name = "aho-corasick" -version = "0.7.20" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783" dependencies = [ "memchr", ] -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - [[package]] name = "approx" version = "0.5.1" @@ -46,37 +37,14 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" -[[package]] -name = "bindgen" -version = "0.58.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f8523b410d7187a43085e7e064416ea32ded16bd0a4e6fc025e21616d01258f" -dependencies = [ - "bitflags", - "cexpr 0.4.0", - "clang-sys", - "clap", - "env_logger", - "lazy_static", - "lazycell", - "log", - "peeking_take_while", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "which 3.1.1", -] - [[package]] name = "bindgen" version = "0.64.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4243e6031260db77ede97ad86c27e501d646a27ab57b59a574f725d98ab1fb4" dependencies = [ - "bitflags", - "cexpr 0.6.0", + "bitflags 1.3.2", + "cexpr", "clang-sys", "lazy_static", "lazycell", @@ -88,7 +56,7 @@ dependencies = [ "rustc-hash", "shlex", "syn 1.0.109", - "which 4.4.0", + "which", ] [[package]] @@ -97,17 +65,32 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + [[package]] name = "camino" -version = "1.1.4" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" + +[[package]] +name = "cc" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c530edf18f37068ac2d977409ed5cd50d53d73bc653c7647b48eb78976ac9ae2" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] [[package]] name = "ccx_rust" version = "0.1.0" dependencies = [ - "bindgen 0.58.1", + "bindgen", "env_logger", "iconv", "leptonica-sys", @@ -117,22 +100,13 @@ dependencies = [ "tesseract-sys", ] -[[package]] -name = "cexpr" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27" -dependencies = [ - "nom 5.1.2", -] - [[package]] name = "cexpr" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" dependencies = [ - "nom 7.1.3", + "nom", ] [[package]] @@ -143,30 +117,15 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clang-sys" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ed9a53e5d4d9c573ae844bfac6872b159cb1d1585a83b29e7a64b7eef7332a" +checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" dependencies = [ "glob", "libc", "libloading", ] -[[package]] -name = "clap" -version = "2.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" -dependencies = [ - "ansi_term", - "atty", - "bitflags", - "strsim", - "textwrap", - "unicode-width", - "vec_map", -] - [[package]] name = "dyn_buf" version = "0.1.0" @@ -175,9 +134,9 @@ checksum = "74c57ab96715773d9cb9789b38eb7cbf04b3c6f5624a9d98f51761603376767c" [[package]] name = "either" -version = "1.8.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "env_logger" @@ -192,6 +151,27 @@ dependencies = [ "termcolor", ] +[[package]] +name = "errno" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "find-crate" version = "0.6.3" @@ -216,6 +196,15 @@ dependencies = [ "libc", ] +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys", +] + [[package]] name = "humantime" version = "2.1.0" @@ -246,20 +235,20 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "leptonica-sys" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "811a92997ff15e0d7323c1e8fa7190331dd02ea50d9d7cfaa4fdc2b21a613a2e" +checksum = "eff3f1dc2f0112411228f8db99ca8a6a1157537a7887b28b1c91fdc4051fb326" dependencies = [ - "bindgen 0.64.0", + "bindgen", "pkg-config", "vcpkg", ] [[package]] name = "libc" -version = "0.2.140" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "libloading" @@ -271,20 +260,23 @@ dependencies = [ "winapi", ] +[[package]] +name = "linux-raw-sys" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128" + [[package]] name = "log" -version = "0.4.17" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" [[package]] name = "minimal-lexical" @@ -292,16 +284,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "nom" -version = "5.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" -dependencies = [ - "memchr", - "version_check", -] - [[package]] name = "nom" version = "7.1.3" @@ -314,18 +296,18 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg", ] [[package]] name = "once_cell" -version = "1.17.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "palette" @@ -353,9 +335,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "peeking_take_while" @@ -365,9 +347,9 @@ checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] name = "phf" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" dependencies = [ "phf_macros", "phf_shared", @@ -375,9 +357,9 @@ dependencies = [ [[package]] name = "phf_generator" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" dependencies = [ "phf_shared", "rand", @@ -385,46 +367,46 @@ dependencies = [ [[package]] name = "phf_macros" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92aacdc5f16768709a569e913f7451034034178b05bdc8acda226659a3dccc66" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" dependencies = [ "phf_generator", "phf_shared", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.32", ] [[package]] name = "phf_shared" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" dependencies = [ "siphasher", ] [[package]] name = "pkg-config" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "proc-macro2" -version = "1.0.52" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.26" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -446,9 +428,21 @@ checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" [[package]] name = "regex" -version = "1.7.1" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" +checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" dependencies = [ "aho-corasick", "memchr", @@ -457,9 +451,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.28" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "rsmpeg" @@ -479,13 +473,26 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustix" +version = "0.38.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7db8590df6dfcd144d22afd1b83b36c21a18d7cbc1dc4bb5295a8712e9eb662" +dependencies = [ + "bitflags 2.4.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + [[package]] name = "rusty_ffmpeg" version = "0.13.1+ffmpeg.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e7c726b08ea3ed199e21f6f4b3a1c23fc56a154be731b4445e4ef9ee004cffc" dependencies = [ - "bindgen 0.64.0", + "bindgen", "camino", "libc", "once_cell", @@ -495,27 +502,35 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.158" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771d4d9c4163ee138805e12c710dd365e4f44be8be0503cb1bb9eb989425d9c9" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +dependencies = [ + "serde_derive", +] [[package]] -name = "shlex" -version = "1.1.0" +name = "serde_derive" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.32", +] [[package]] -name = "siphasher" -version = "0.3.10" +name = "shlex" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" +checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380" [[package]] -name = "strsim" -version = "0.8.0" +name = "siphasher" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "syn" @@ -530,9 +545,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.4" +version = "2.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c622ae390c9302e214c31013517c2061ecb2699935882c60a9b37f82f8625ae" +checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2" dependencies = [ "proc-macro2", "quote", @@ -554,39 +569,30 @@ version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd33f6f216124cfaf0fa86c2c0cdf04da39b6257bd78c5e44fa4fa98c3a5857b" dependencies = [ - "bindgen 0.64.0", + "bindgen", "leptonica-sys", "pkg-config", "vcpkg", ] -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] - [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" dependencies = [ "proc-macro2", "quote", - "syn 2.0.4", + "syn 2.0.32", ] [[package]] @@ -600,15 +606,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" - -[[package]] -name = "unicode-width" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" [[package]] name = "vcpkg" @@ -616,36 +616,16 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" -[[package]] -name = "vec_map" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - [[package]] name = "which" -version = "3.1.1" +version = "4.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724" -dependencies = [ - "libc", -] - -[[package]] -name = "which" -version = "4.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" dependencies = [ "either", - "libc", + "home", "once_cell", + "rustix", ] [[package]] @@ -678,3 +658,69 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index e8edc2096..027d76460 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -20,7 +20,7 @@ tesseract-sys = { version = "0.5.14", optional = true, default-features = false} leptonica-sys = { version = "0.4.3", optional = true, default-features = false} [build-dependencies] -bindgen = "0.58.1" +bindgen = "0.64.0" [features] hardsubx_ocr = ["rsmpeg", "tesseract-sys", "leptonica-sys"] From 79aaf8659390850d570a96a764d8b7f29557ce6a Mon Sep 17 00:00:00 2001 From: Prateek Sunal Date: Mon, 23 Oct 2023 19:54:48 +0530 Subject: [PATCH 02/27] [FIX] #1549 Configure Script (#1574) * fix: #1549 backticks * fix: use single equal to --- linux/configure.ac | 18 +++++++++--------- mac/configure.ac | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/linux/configure.ac b/linux/configure.ac index d6080cd13..2bc47a34e 100644 --- a/linux/configure.ac +++ b/linux/configure.ac @@ -15,7 +15,7 @@ AC_PROG_MAKE_SET #Checks for "pkg-config" utility AC_MSG_CHECKING([pkg-config m4 macros]) -if test m4_ifdef([PKG_CHECK_MODULES], [yes], [no]) == yes; then +if test m4_ifdef([PKG_CHECK_MODULES], [yes], [no]) = yes; then AC_MSG_RESULT([yes]); else AC_MSG_RESULT([no]); @@ -140,21 +140,21 @@ AS_IF([ test x$hardsubx = xtrue && test $HAS_AVUTIL -gt 0 ], [AC_MSG_NOTICE(avut AS_IF([ test x$hardsubx = xtrue && test ! $HAS_AVUTIL -gt 0 ], [AC_MSG_ERROR(avutil library not found. Please install the avutil library before proceeding)]) AS_IF([ test x$hardsubx = xtrue && test $HAS_SWSCALE -gt 0 ], [AC_MSG_NOTICE(swscale library found)]) AS_IF([ test x$hardsubx = xtrue && test ! $HAS_SWSCALE -gt 0 ], [AC_MSG_ERROR(swscale library not found. Please install the swscale library before proceeding)]) -AS_IF([ (test x$ocr = xtrue || test x$hardsubx = xtrue) && test $HAS_TESSERACT -gt 0 ], [TESS_VERSION=`tesseract --version 2>&1 | grep tesseract` && AC_MSG_NOTICE(tesseract library found... $TESS_VERSION)]) +AS_IF([ (test x$ocr = xtrue || test x$hardsubx = xtrue) && test $HAS_TESSERACT -gt 0 ], [TESS_VERSION=$(tesseract --version 2>&1 | grep tesseract) && AC_MSG_NOTICE(tesseract library found... $TESS_VERSION)]) AS_IF([ (test x$ocr = xtrue || test x$hardsubx = xtrue) && test ! $HAS_TESSERACT -gt 0 ], [AC_MSG_ERROR(tesserect library not found. Please install the tesseract library before proceeding)]) -AS_IF([ (test x$ocr = xtrue || test x$hardsubx = xtrue) && test $HAS_LEPT -gt 0 ], [LEPT_VERSION=`tesseract --version 2>&1 | grep leptonica` && AC_MSG_NOTICE(leptonica library found... $LEPT_VERSION)]) +AS_IF([ (test x$ocr = xtrue || test x$hardsubx = xtrue) && test $HAS_LEPT -gt 0 ], [LEPT_VERSION=$(tesseract --version 2>&1 | grep leptonica) && AC_MSG_NOTICE(leptonica library found... $LEPT_VERSION)]) AS_IF([ (test x$ocr = xtrue || test x$hardsubx = xtrue) && test ! $HAS_LEPT -gt 0 ], [AC_MSG_ERROR(leptonica library not found. Please install the leptonica library before proceeding)]) #AM_CONDITIONAL(s) for setting values to enable/disable flags in Makefile.am AM_CONDITIONAL(HARDSUBX_IS_ENABLED, [ test x$hardsubx = xtrue ]) AM_CONDITIONAL(OCR_IS_ENABLED, [ test x$ocr = xtrue || test x$hardsubx = xtrue ]) AM_CONDITIONAL(FFMPEG_IS_ENABLED, [ test x$ffmpeg = xtrue ]) -AM_CONDITIONAL(TESSERACT_PRESENT, [ test ! -z `pkg-config --libs-only-l --silence-errors tesseract` ]) -AM_CONDITIONAL(TESSERACT_PRESENT_RPI, [ test -d "/usr/include/tesseract" && test `ls -A /usr/include/tesseract | wc -l` -gt 0 ]) -AM_CONDITIONAL(SYS_IS_LINUX, [ test `uname -s` = "Linux"]) -AM_CONDITIONAL(SYS_IS_MAC, [ test `uname -s` = "Darwin"]) -AM_CONDITIONAL(SYS_IS_APPLE_SILICON, [ test `uname -a | awk '{print $NF}'` = "arm64" ]) -AM_CONDITIONAL(SYS_IS_64_BIT,[test `getconf LONG_BIT` = "64"]) +AM_CONDITIONAL(TESSERACT_PRESENT, [ test ! -z $(pkg-config --libs-only-l --silence-errors tesseract) ]) +AM_CONDITIONAL(TESSERACT_PRESENT_RPI, [ test -d "/usr/include/tesseract" && test $(ls -A /usr/include/tesseract | wc -l) -gt 0 ]) +AM_CONDITIONAL(SYS_IS_LINUX, [ test $(uname -s) = "Linux"]) +AM_CONDITIONAL(SYS_IS_MAC, [ test $(uname -s) = "Darwin"]) +AM_CONDITIONAL(SYS_IS_APPLE_SILICON, [ test $(uname -a | awk '{print $NF}') = "arm64" ]) +AM_CONDITIONAL(SYS_IS_64_BIT,[test $(getconf LONG_BIT) = "64"]) AC_CONFIG_FILES([Makefile]) AC_OUTPUT diff --git a/mac/configure.ac b/mac/configure.ac index 53b841d90..2ddf6dd6d 100644 --- a/mac/configure.ac +++ b/mac/configure.ac @@ -15,7 +15,7 @@ AC_PROG_MAKE_SET #Checks for "pkg-config" utility AC_MSG_CHECKING([pkg-config m4 macros]) -if test m4_ifdef([PKG_CHECK_MODULES], [yes], [no]) == yes; then +if test m4_ifdef([PKG_CHECK_MODULES], [yes], [no]) = yes; then AC_MSG_RESULT([yes]); else AC_MSG_RESULT([no]); @@ -139,21 +139,21 @@ AS_IF([ test x$hardsubx = xtrue && test $HAS_AVUTIL -gt 0 ], [AC_MSG_NOTICE(avut AS_IF([ test x$hardsubx = xtrue && test ! $HAS_AVUTIL -gt 0 ], [AC_MSG_ERROR(avutil library not found. Please install the avutil library before proceeding)]) AS_IF([ test x$hardsubx = xtrue && test $HAS_SWSCALE -gt 0 ], [AC_MSG_NOTICE(swscale library found)]) AS_IF([ test x$hardsubx = xtrue && test ! $HAS_SWSCALE -gt 0 ], [AC_MSG_ERROR(swscale library not found. Please install the swscale library before proceeding)]) -AS_IF([ (test x$ocr = xtrue || test x$hardsubx = xtrue) && test $HAS_TESSERACT -gt 0 ], [TESS_VERSION=`tesseract --version 2>&1 | grep tesseract` && AC_MSG_NOTICE(tesseract library found... $TESS_VERSION)]) +AS_IF([ (test x$ocr = xtrue || test x$hardsubx = xtrue) && test $HAS_TESSERACT -gt 0 ], [TESS_VERSION=$(tesseract --version 2>&1 | grep tesseract) && AC_MSG_NOTICE(tesseract library found... $TESS_VERSION)]) AS_IF([ (test x$ocr = xtrue || test x$hardsubx = xtrue) && test ! $HAS_TESSERACT -gt 0 ], [AC_MSG_ERROR(tesserect library not found. Please install the tesseract library before proceeding)]) -AS_IF([ (test x$ocr = xtrue || test x$hardsubx = xtrue) && test $HAS_LEPT -gt 0 ], [LEPT_VERSION=`tesseract --version 2>&1 | grep leptonica` && AC_MSG_NOTICE(leptonica library found... $LEPT_VERSION)]) +AS_IF([ (test x$ocr = xtrue || test x$hardsubx = xtrue) && test $HAS_LEPT -gt 0 ], [LEPT_VERSION=$(tesseract --version 2>&1 | grep leptonica) && AC_MSG_NOTICE(leptonica library found... $LEPT_VERSION)]) AS_IF([ (test x$ocr = xtrue || test x$hardsubx = xtrue) && test ! $HAS_LEPT -gt 0 ], [AC_MSG_ERROR(leptonica library not found. Please install the leptonica library before proceeding)]) #AM_CONDITIONAL(s) for setting values to enable/disable flags in Makefile.am AM_CONDITIONAL(HARDSUBX_IS_ENABLED, [ test x$hardsubx = xtrue ]) AM_CONDITIONAL(OCR_IS_ENABLED, [ test x$ocr = xtrue || test x$hardsubx = xtrue ]) AM_CONDITIONAL(FFMPEG_IS_ENABLED, [ test x$ffmpeg = xtrue ]) -AM_CONDITIONAL(TESSERACT_PRESENT, [ test ! -z `pkg-config --libs-only-l --silence-errors tesseract` ]) -AM_CONDITIONAL(TESSERACT_PRESENT_RPI, [ test -d "/usr/include/tesseract" && test `ls -A /usr/include/tesseract | wc -l` -gt 0 ]) -AM_CONDITIONAL(SYS_IS_LINUX, [ test `uname -s` = "Linux"]) -AM_CONDITIONAL(SYS_IS_MAC, [ test `uname -s` = "Darwin"]) -AM_CONDITIONAL(SYS_IS_APPLE_SILICON, [ test `uname -a | awk '{print $NF}'` = "arm64" ]) -AM_CONDITIONAL(SYS_IS_64_BIT,[test `getconf LONG_BIT` = "64"]) +AM_CONDITIONAL(TESSERACT_PRESENT, [ test ! -z $(pkg-config --libs-only-l --silence-errors tesseract) ]) +AM_CONDITIONAL(TESSERACT_PRESENT_RPI, [ test -d "/usr/include/tesseract" && test $(ls -A /usr/include/tesseract | wc -l) -gt 0 ]) +AM_CONDITIONAL(SYS_IS_LINUX, [ test $(uname -s) = "Linux"]) +AM_CONDITIONAL(SYS_IS_MAC, [ test $(uname -s) = "Darwin"]) +AM_CONDITIONAL(SYS_IS_APPLE_SILICON, [ test $(uname -a | awk '{print $NF}') = "arm64" ]) +AM_CONDITIONAL(SYS_IS_64_BIT,[test $(getconf LONG_BIT) = "64"]) AC_CONFIG_FILES([Makefile]) AC_OUTPUT From 376ff831616919e092b53353f3799654d86d0759 Mon Sep 17 00:00:00 2001 From: Om Thorat <76207818+Om-Thorat@users.noreply.github.com> Date: Mon, 11 Dec 2023 18:56:06 +0530 Subject: [PATCH 03/27] [FIX] Compilation.md - Added a note for Ubuntu 23.10 (#1581) * [FIX] Added a note for Ubuntu 23.10 libgpac-dev isn't available on Ubuntu 23.10 (Mantic) added a note instructing to build it from source instead. * [FIX] Added build instructions for Ubuntu 23.10 and later libgpac-dev isn't available in Ubuntu 23.10 and later, hence causing the build to fail. added the instructions to build it from source. --- docs/COMPILATION.MD | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/COMPILATION.MD b/docs/COMPILATION.MD index 7e91b73a6..7189f71f7 100644 --- a/docs/COMPILATION.MD +++ b/docs/COMPILATION.MD @@ -17,7 +17,7 @@ git clone https://github.com/CCExtractor/ccextractor.git Debian: ```bash -sudo apt-get install -y libglew-dev libglfw3-dev cmake gcc libcurl4-gnutls-dev tesseract-ocr libtesseract-dev libleptonica-dev clang libclang-dev +sudo apt-get install -y libgpac-dev libglew-dev libglfw3-dev cmake gcc libcurl4-gnutls-dev tesseract-ocr libtesseract-dev libleptonica-dev clang libclang-dev ``` RHEL: @@ -33,6 +33,8 @@ sudo paru -S glew glfw curl tesseract leptonica cmake gcc clang Rust 1.54 or above is also required. [Install Rust](https://www.rust-lang.org/tools/install). Check specific compilation methods below, on how to compile without rust. +**Note:** On Ubuntu Version 23.10 (Mantic) and later, `libgpac-dev` isn't available, you should build gpac from source by following the easy build instructions [here](https://github.com/gpac/gpac/wiki/GPAC-Build-Guide-for-Linux) + **Note:** On Ubuntu Version 18.04 (Bionic) and later, `libtesseract-dev` is installed rather than `tesseract-ocr-dev`, which does not exist anymore. **Note:** On Ubuntu Version 14.04 (Trusty) and earlier, you should build leptonica and tesseract from source From d2f17deb2c5a299f6ba30c02440fb0f2fb49d682 Mon Sep 17 00:00:00 2001 From: Vitaly Lysenkov Date: Mon, 8 Jan 2024 19:30:14 +0100 Subject: [PATCH 04/27] **[FIX]** fix infinite loop in MP4 file type detector and processor (#1566) * Update stream_functions.c: fix MP4 file type detector On bad inputs containing e.g. the following sequence of bytes within the first 1MiB "ff ff ff ff 6d 65 74 61" `detect_stream_type` was executing an infinite loop because "ff ff ff ff" was interpreted as a length of the candidate "meta" MP4 box, caused the size_t overflow inside `isValidMP4Box` which pointed `nextBoxLocation` to the previous byte and the execution flow processed the same "meta" again. * Update CHANGES.TXT * Treat a candidate MP4 box as invalid instead of bailing out * Fix stuck mp4 processing in `process_avc_sample` On corrupted inputs it could read data past the sample end and also get stuck in an infinite loop. * Fix the stats code to not count zero-sized NALs and avoid dereferencing memory past the NAL end * Add comment. * Format changes --- docs/CHANGES.TXT | 1 + src/lib_ccx/mp4.c | 27 +++++++++++++++++++++++++-- src/lib_ccx/stream_functions.c | 2 +- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/docs/CHANGES.TXT b/docs/CHANGES.TXT index 5471ea1a9..214584c72 100644 --- a/docs/CHANGES.TXT +++ b/docs/CHANGES.TXT @@ -21,6 +21,7 @@ - Fix: Repeated values for enums - Cleanup: Remove the (unmaintained) Nuklear GUI code - Cleanup: Reduce the amount of Windows build options in the project file +- Fix: infinite loop in MP4 file type detector. 0.94 (2021-12-14) ----------------- diff --git a/src/lib_ccx/mp4.c b/src/lib_ccx/mp4.c index 1b5c45119..05df43fe0 100644 --- a/src/lib_ccx/mp4.c +++ b/src/lib_ccx/mp4.c @@ -51,6 +51,16 @@ static int process_avc_sample(struct lib_ccx_ctx *ctx, u32 timescale, GF_AVCConf { u32 nal_length; + if (i + c->nal_unit_size > s->dataLength) + { + mprint("Corrupted packet detected in process_avc_sample. dataLength " + "%u is less than index %u + nal_unit_size %u. Ignoring.\n", + s->dataLength, i, c->nal_unit_size); + // The packet is likely corrupted, it's unsafe to read this many bytes + // even to detect the length of the next `nal`. Ignoring this error, + // hopefully the outer loop in `process_avc_track` can recover. + return status; + } switch (c->nal_unit_size) { case 1: @@ -63,15 +73,28 @@ static int process_avc_sample(struct lib_ccx_ctx *ctx, u32 timescale, GF_AVCConf nal_length = bswap32(*(long *)&s->data[i]); break; } + const u32 previous_index = i; i += c->nal_unit_size; + if (i + nal_length <= previous_index || i + nal_length > s->dataLength) + { + mprint("Corrupted sample detected in process_avc_sample. dataLength %u " + "is less than index %u + nal_unit_size %u + nal_length %u. Ignoring.\n", + s->dataLength, previous_index, c->nal_unit_size, nal_length); + // The packet is likely corrupted, it's unsafe to procell nal_length bytes + // because they are past the sample end. Ignoring this error, hopefully + // the outer loop in `process_avc_track` can recover. + return status; + } s_nalu_stats.total += 1; - s_nalu_stats.type[s->data[i] & 0x1F] += 1; - temp_debug = 0; if (nal_length > 0) + { + // s->data[i] is only relevant and safe to access here. + s_nalu_stats.type[s->data[i] & 0x1F] += 1; do_NAL(enc_ctx, dec_ctx, (unsigned char *)&(s->data[i]), nal_length, sub); + } i += nal_length; } // outer for assert(i == s->dataLength); diff --git a/src/lib_ccx/stream_functions.c b/src/lib_ccx/stream_functions.c index dd1728d95..14d2372e8 100644 --- a/src/lib_ccx/stream_functions.c +++ b/src/lib_ccx/stream_functions.c @@ -99,7 +99,7 @@ void detect_stream_type(struct ccx_demuxer *ctx) while (idx < ctx->startbytes_avail - 8) { // Check if we have a valid box - if (isValidMP4Box(ctx->startbytes, idx, &nextBoxLocation, &boxScore)) + if (isValidMP4Box(ctx->startbytes, idx, &nextBoxLocation, &boxScore) && nextBoxLocation > idx) { idx = nextBoxLocation; // If the box is valid, a new box should be found on the next location... Not somewhere in between. if (boxScore > 7) From 870e8bb6ac76c9eba7ca3184ea0bf0d36cbb44e9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Jan 2024 19:33:21 +0100 Subject: [PATCH 05/27] Bump AButler/upload-release-assets from 2.0 to 3.0 (#1577) Bumps [AButler/upload-release-assets](https://github.com/abutler/upload-release-assets) from 2.0 to 3.0. - [Release notes](https://github.com/abutler/upload-release-assets/releases) - [Commits](https://github.com/abutler/upload-release-assets/compare/v2.0...v3.0) --- updated-dependencies: - dependency-name: AButler/upload-release-assets dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2a2d2f147..89de3ed8e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -62,7 +62,7 @@ jobs: run: wix build -ext "$HOME\.wix\extensions\WixToolset.UI.wixext\4.0.0-preview.0\tools\WixToolset.UI.wixext.dll" -d "AppVersion=${{ steps.get_version.outputs.VERSION }}.0.0" -o CCExtractor.msi installer.wxs working-directory: ./windows - name: Upload as asset - uses: AButler/upload-release-assets@v2.0 + uses: AButler/upload-release-assets@v3.0 with: files: './windows/CCExtractor.msi;./windows/CCExtractor_win_portable.zip' repo-token: ${{ secrets.GITHUB_TOKEN }} @@ -75,7 +75,7 @@ jobs: - name: Create .tar.gz without git and windows folders run: tar -pczf ./ccextractor_minimal.tar.gz --exclude "ccextractor/windows" --exclude "ccextractor/.git" ccextractor - name: Upload as asset - uses: AButler/upload-release-assets@v2.0 + uses: AButler/upload-release-assets@v3.0 with: files: './ccextractor_minimal.tar.gz' repo-token: ${{ secrets.GITHUB_TOKEN }} From eef2591c25d2401ea39e60ccf1738f565589da08 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Jan 2024 20:00:59 +0100 Subject: [PATCH 06/27] Bump actions/upload-artifact from 3 to 4 (#1587) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3 to 4. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build_linux.yml | 2 +- .github/workflows/build_mac.yml | 2 +- .github/workflows/build_windows.yml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml index 4bb225cfb..2a48805bb 100644 --- a/.github/workflows/build_linux.yml +++ b/.github/workflows/build_linux.yml @@ -38,7 +38,7 @@ jobs: run: mkdir ./linux/artifacts - name: Copy release artifact run: cp ./linux/ccextractor ./linux/artifacts/ - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: CCExtractor Linux build path: ./linux/artifacts diff --git a/.github/workflows/build_mac.yml b/.github/workflows/build_mac.yml index 219704e6a..106d370da 100644 --- a/.github/workflows/build_mac.yml +++ b/.github/workflows/build_mac.yml @@ -38,7 +38,7 @@ jobs: run: mkdir ./mac/artifacts - name: Copy release artifact run: cp ./mac/ccextractor ./mac/artifacts/ - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: CCExtractor mac build path: ./mac/artifacts diff --git a/.github/workflows/build_windows.yml b/.github/workflows/build_windows.yml index 37c793a92..ade99ac50 100644 --- a/.github/workflows/build_windows.yml +++ b/.github/workflows/build_windows.yml @@ -57,7 +57,7 @@ jobs: - name: Display version information run: ./ccextractorwinfull.exe --version working-directory: ./windows/x64/Release-Full - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: CCExtractor Windows Release build path: | @@ -99,7 +99,7 @@ jobs: - name: Display version information run: ./ccextractorwinfull.exe --version working-directory: ./windows/x64/Debug-Full - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: CCExtractor Windows Debug build path: | From 63a259a31352d9a897ee05114126e02de518b8d6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Jan 2024 20:01:49 +0100 Subject: [PATCH 07/27] Bump actions/checkout from 3 to 4 (#1567) Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build_linux.yml | 10 +++++----- .github/workflows/build_mac.yml | 12 ++++++------ .github/workflows/build_windows.yml | 4 ++-- .github/workflows/format.yml | 4 ++-- .github/workflows/release.yml | 4 ++-- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml index 2a48805bb..51a1e5bcb 100644 --- a/.github/workflows/build_linux.yml +++ b/.github/workflows/build_linux.yml @@ -27,7 +27,7 @@ jobs: steps: - name: Install dependencies run: sudo apt update && sudo apt-get install libgpac-dev libtesseract-dev - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: build run: ./build working-directory: ./linux @@ -47,7 +47,7 @@ jobs: steps: - name: Install dependencies run: sudo apt update && sudo apt-get install libgpac-dev - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: run autogen run: ./autogen.sh working-directory: ./linux @@ -65,7 +65,7 @@ jobs: steps: - name: Install dependencies run: sudo apt update && sudo apt-get install libgpac-dev - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: cmake run: mkdir build && cd build && cmake ../src - name: build @@ -76,7 +76,7 @@ jobs: cmake_ocr_hardsubx: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install dependencies run: sudo apt update && sudo apt install libgpac-dev libtesseract-dev libavformat-dev libavdevice-dev libswscale-dev yasm - name: cmake @@ -94,7 +94,7 @@ jobs: steps: - name: Install dependencies run: sudo apt update && sudo apt-get install libgpac-dev - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: cache uses: actions/cache@v3 with: diff --git a/.github/workflows/build_mac.yml b/.github/workflows/build_mac.yml index 106d370da..135d1e622 100644 --- a/.github/workflows/build_mac.yml +++ b/.github/workflows/build_mac.yml @@ -27,7 +27,7 @@ jobs: steps: - name: Install dependencies run: brew install pkg-config autoconf automake libtool tesseract leptonica gpac - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: build run: ./build.command working-directory: ./mac @@ -45,7 +45,7 @@ jobs: build_autoconf: runs-on: macos-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install dependencies run: brew install pkg-config autoconf automake libtool gpac - name: run autogen @@ -63,10 +63,10 @@ jobs: cmake: runs-on: macos-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: dependencies run: brew install gpac - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: cmake run: mkdir build && cd build && cmake ../src - name: build @@ -77,7 +77,7 @@ jobs: cmake_ocr_hardsubx: runs-on: macos-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install dependencies run: brew install pkg-config autoconf automake libtool tesseract leptonica gpac ffmpeg - name: cmake @@ -93,7 +93,7 @@ jobs: build_rust: runs-on: macos-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: cache uses: actions/cache@v3 with: diff --git a/.github/workflows/build_windows.yml b/.github/workflows/build_windows.yml index ade99ac50..3ecbf1c8b 100644 --- a/.github/workflows/build_windows.yml +++ b/.github/workflows/build_windows.yml @@ -25,7 +25,7 @@ jobs: runs-on: windows-2019 steps: - name: Check out repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup MSBuild.exe uses: microsoft/setup-msbuild@v1.3.1 - name: Install llvm and clang @@ -67,7 +67,7 @@ jobs: runs-on: windows-2019 steps: - name: Check out repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup MSBuild.exe uses: microsoft/setup-msbuild@v1.3.1 - name: Install llvm and clang diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 0cc02cb51..98d580264 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -19,7 +19,7 @@ jobs: format: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Format code run: | find src/ -type f -not -path "src/thirdparty/*" -not -path "src/lib_ccx/zvbi/*" -name '*.c' -not -path "src/GUI/icon_data.c" | xargs clang-format -i @@ -30,7 +30,7 @@ jobs: run: working-directory: ./src/rust steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: cache uses: actions/cache@v3 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 89de3ed8e..60ef7079a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,7 +10,7 @@ jobs: runs-on: windows-latest steps: - name: Check out repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Get the version id: get_version run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\/v/} @@ -69,7 +69,7 @@ jobs: create_linux_package: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: path: ./ccextractor - name: Create .tar.gz without git and windows folders From bce63b88dcd6a9bfeff2cad36ae4a6a5511ec29b Mon Sep 17 00:00:00 2001 From: Prateek Sunal Date: Sun, 14 Jan 2024 23:17:13 +0530 Subject: [PATCH 08/27] [FIX] Compatibility of Arguments in C (#1564) * feat: breaking all parameters * fix: some parameters * fix: many things * fix: error * fix: -h * fix: more parameters * fix: add dash to help commands * fix: help for output-field * fix: single dash * fix: --out and --in * fix: move notes to the end of help menu * fix: final changes to notes * fix: extra spacing * fix: wrong formatting of parenthesis --- src/lib_ccx/params.c | 898 ++++++++++++++++++++++--------------------- 1 file changed, 452 insertions(+), 446 deletions(-) diff --git a/src/lib_ccx/params.c b/src/lib_ccx/params.c index 1c06588d8..eb1562e50 100644 --- a/src/lib_ccx/params.c +++ b/src/lib_ccx/params.c @@ -356,58 +356,45 @@ void print_usage(void) mprint(" -o outputfilename: Use -o parameters to define output filename if you don't\n"); mprint(" like the default ones (same as infile plus _1 or _2 when\n"); mprint(" needed and file extension, e.g. .srt).\n"); - mprint(" -stdout: Write output to stdout (console) instead of file. If\n"); + mprint(" --stdout: Write output to stdout (console) instead of file. If\n"); mprint(" stdout is used, then -o can't be used. Also\n"); - mprint(" -stdout will redirect all messages to stderr (error).\n"); - mprint(" -pesheader: Dump the PES Header to stdout (console). This is\n"); + mprint(" --stdout will redirect all messages to stderr (error).\n"); + mprint(" --pesheader: Dump the PES Header to stdout (console). This is\n"); mprint(" used for debugging purposes to see the contents\n"); mprint(" of each PES packet header.\n"); - mprint(" -debugdvbsub: Write the DVB subtitle debug traces to console.\n"); - mprint(" -ignoreptsjumps: Ignore PTS jumps (default).\n"); - mprint(" -fixptsjumps: fix pts jumps. Use this parameter if you\n"); + mprint(" --debugdvbsub: Write the DVB subtitle debug traces to console.\n"); + mprint(" --ignoreptsjumps: Ignore PTS jumps (default).\n"); + mprint(" --fixptsjumps: fix pts jumps. Use this parameter if you\n"); mprint(" experience timeline resets/jumps in the output.\n"); - mprint(" -stdin: Reads input from stdin (console) instead of file.\n"); + mprint(" --stdin: Reads input from stdin (console) instead of file.\n"); mprint(" Alternatively, - can be used instead of -stdin\n"); - mprint("You can pass as many input files as you need. They will be processed in order.\n"); - mprint("If a file name is suffixed by +, ccextractor will try to follow a numerical\n"); - mprint("sequence. For example, DVD001.VOB+ means DVD001.VOB, DVD002.VOB and so on\n"); - mprint("until there are no more files.\n"); - mprint("Output will be one single file (either raw or srt). Use this if you made your\n"); - mprint("recording in several cuts (to skip commercials for example) but you want one\n"); - mprint("subtitle file with contiguous timing.\n\n"); mprint("Output file segmentation:\n"); - mprint(" -outinterval x output in interval of x seconds\n"); - mprint(" --segmentonkeyonly -key: When segmenting files, do it only after a I frame\n"); + mprint(" --outinterval x output in interval of x seconds\n"); + mprint(" --segmentonkeyonly: When segmenting files, do it only after a I frame\n"); mprint(" trying to behave like FFmpeg\n\n"); mprint("Network support:\n"); - mprint(" -udp port: Read the input via UDP (listening in the specified port)\n"); - mprint(" instead of reading a file.\n\n"); - mprint(" -udp [host:]port: Read the input via UDP (listening in the specified\n"); - mprint(" port) instead of reading a file. Host can be a\n"); - mprint(" hostname or IPv4 address. If host is not specified\n"); - mprint(" then listens on the local host.\n\n"); - mprint(" -udp [src@host:]port: Read the input via UDP (listening in the specified\n"); + mprint(" --udp [[src@]host:]port: Read the input via UDP (listening in the specified\n"); mprint(" port) instead of reading a file. Host and src can be a\n"); mprint(" hostname or IPv4 address. If host is not specified\n"); mprint(" then listens on the local host.\n\n"); - mprint(" -sendto host[:port]: Sends data in BIN format to the server\n"); + mprint(" --sendto host[:port]: Sends data in BIN format to the server\n"); mprint(" according to the CCExtractor's protocol over\n"); mprint(" TCP. For IPv6 use [address]:port\n"); - mprint(" -tcp port: Reads the input data in BIN format according to\n"); + mprint(" --tcp port: Reads the input data in BIN format according to\n"); mprint(" CCExtractor's protocol, listening specified port on the\n"); mprint(" local host\n"); - mprint(" -tcppassword password: Sets server password for new connections to\n"); + mprint(" --tcp-password password: Sets server password for new connections to\n"); mprint(" tcp server\n"); - mprint(" -tcpdesc description: Sends to the server short description about\n"); + mprint(" --tcp-description description: Sends to the server short description about\n"); mprint(" captions e.g. channel name or file name\n"); mprint("Options that affect what will be processed:\n"); - mprint(" -1, -2, -12: Output Field 1 data, Field 2 data, or both\n"); - mprint(" (DEFAULT is -1)\n"); + mprint(" --output-field 1 / 2 / both: Output Field 1 data, Field 2 data, or both\n"); + mprint(" (DEFAULT is 1)\n"); mprint("Use --append to prevent overwriting of existing files. The output will be\n"); mprint(" appended instead.\n"); - mprint(" -cc2: When in srt/sami mode, process captions in channel 2\n"); - mprint(" instead of channel 1. Alternatively, -CC2 can also be used.\n"); - mprint("-svc --service N1[cs1],N2[cs2]...:\n"); + mprint(" --cc2: When in srt/sami mode, process captions in channel 2\n"); + mprint(" instead of channel 1. Alternatively, --CC2 can also be used.\n"); + mprint(" --service N1[cs1],N2[cs2]...:\n"); mprint(" Enable CEA-708 (DTVCC) captions processing for the listed\n"); mprint(" services. The parameter is a comma delimited list\n"); mprint(" of services numbers, such as \"1,2\" to process the\n"); @@ -421,9 +408,6 @@ void print_usage(void) mprint(" UTF-8 using iconv. See iconv documentation to check if\n"); mprint(" required encoding/charset is supported.\n"); mprint("\n"); - mprint("In general, if you want English subtitles you don't need to use these options\n"); - mprint("as they are broadcast in field 1, channel 1. If you want the second language\n"); - mprint("(usually Spanish) you may need to try -2, or -cc2, or both.\n\n"); mprint("Input formats:\n"); mprint(" With the exception of McPoodle's raw format, which is just the closed\n"); mprint(" caption data with no other info, CCExtractor can usually detect the\n"); @@ -444,9 +428,9 @@ void print_usage(void) #ifdef WTV_DEBUG mprint(" hex -> Hexadecimal dump as generated by wtvccdump.\n"); #endif - mprint(" -ts, -ps, -es, -mp4, -wtv, -mkv and -asf/--dvr-ms can be used as shorts.\n\n"); + mprint(" --ts, --ps, --es, --mp4, --wtv, --mkv and --asf/--dvr-ms can be used as shorts.\n\n"); mprint("Output formats:\n\n"); - mprint(" -out=format\n\n"); + mprint(" --out=format\n\n"); mprint(" where format is one of these:\n"); mprint(" srt -> SubRip (default, so not actually needed).\n"); mprint(" ass/ssa -> SubStation Alpha.\n"); @@ -477,27 +461,27 @@ void print_usage(void) mprint(" report -> Prints to stdout information about captions\n"); mprint(" in specified input. Don't produce any file\n"); mprint(" output\n\n"); - mprint(" -srt, -dvdraw, -sami, -webvtt, -txt, -ttxt and -null can be used as shorts.\n\n"); + mprint(" --srt, --dvdraw, --sami, --webvtt, --txt, --ttxt and --null can be used as shorts.\n\n"); mprint("Options that affect how input files will be processed.\n"); - mprint(" -gt --goptime: Use GOP for timing instead of PTS. This only applies\n"); + mprint(" --goptime: Use GOP for timing instead of PTS. This only applies\n"); mprint(" to Program or Transport Streams with MPEG2 data and\n"); mprint(" overrides the default PTS timing.\n"); mprint(" GOP timing is always used for Elementary Streams.\n"); - mprint(" -nogt --nogoptime: Never use GOP timing (use PTS), even if ccextractor\n"); + mprint(" --no-goptime: Never use GOP timing (use PTS), even if ccextractor\n"); mprint(" detects GOP timing is the reasonable choice.\n"); - mprint(" -fp --fixpadding: Fix padding - some cards (or providers, or whatever)\n"); + mprint(" --fixpadding: Fix padding - some cards (or providers, or whatever)\n"); mprint(" seem to send 0000 as CC padding instead of 8080. If you\n"); mprint(" get bad timing, this might solve it.\n"); - mprint(" -90090: Use 90090 (instead of 90000) as MPEG clock frequency.\n"); + mprint(" --90090: Use 90090 (instead of 90000) as MPEG clock frequency.\n"); mprint(" (reported to be needed at least by Panasonic DMR-ES15\n"); mprint(" DVD Recorder)\n"); - mprint(" -ve --videoedited: By default, ccextractor will process input files in\n"); + mprint(" --videoedited: By default, ccextractor will process input files in\n"); mprint(" sequence as if they were all one large file (i.e.\n"); mprint(" split by a generic, non video-aware tool. If you\n"); mprint(" are processing video hat was split with a editing\n"); - mprint(" tool, use -ve so ccextractor doesn't try to rebuild\n"); + mprint(" tool, use --ve so ccextractor doesn't try to rebuild\n"); mprint(" the original timing.\n"); mprint(" -s --stream [secs]: Consider the file as a continuous stream that is\n"); mprint(" growing as ccextractor processes it, so don't try\n"); @@ -510,80 +494,73 @@ void print_usage(void) mprint(" but not kill ccextractor externally.\n"); mprint(" Note: If -s is used then only one input file is\n"); mprint(" allowed.\n"); - mprint(" -poc --usepicorder: Use the pic_order_cnt_lsb in AVC/H.264 data streams\n"); + mprint(" --usepicorder: Use the pic_order_cnt_lsb in AVC/H.264 data streams\n"); mprint(" to order the CC information. The default way is to\n"); mprint(" use the PTS information. Use this switch only when\n"); mprint(" needed.\n"); - mprint(" -myth: Force MythTV code branch.\n"); - mprint(" -nomyth: Disable MythTV code branch.\n"); + mprint(" --myth: Force MythTV code branch.\n"); + mprint(" --no-myth: Disable MythTV code branch.\n"); mprint(" The MythTV branch is needed for analog captures where\n"); mprint(" the closed caption data is stored in the VBI, such as\n"); mprint(" those with bttv cards (Hauppage 250 for example). This\n"); mprint(" is detected automatically so you don't need to worry\n"); mprint(" about this unless autodetection doesn't work for you.\n"); - mprint(" -wtvconvertfix: This switch works around a bug in Windows 7's built in\n"); + mprint(" --wtvconvertfix: This switch works around a bug in Windows 7's built in\n"); mprint(" software to convert *.wtv to *.dvr-ms. For analog NTSC\n"); mprint(" recordings the CC information is marked as digital\n"); mprint(" captions. Use this switch only when needed.\n"); - mprint(" -wtvmpeg2: Read the captions from the MPEG2 video stream rather\n"); + mprint(" --wtvmpeg2: Read the captions from the MPEG2 video stream rather\n"); mprint(" than the captions stream in WTV files\n"); - mprint(" -pn --program-number: In TS mode, specifically select a program to process.\n"); + mprint(" --program-number: In TS mode, specifically select a program to process.\n"); mprint(" Not needed if the TS only has one. If this parameter\n"); mprint(" is not specified and CCExtractor detects more than one\n"); mprint(" program in the input, it will list the programs found\n"); mprint(" and terminate without doing anything, unless\n"); - mprint(" -autoprogram (see below) is used.\n"); - mprint(" -autoprogram: If there's more than one program in the stream, just use\n"); + mprint(" --autoprogram (see below) is used.\n"); + mprint(" --autoprogram: If there's more than one program in the stream, just use\n"); mprint(" the first one we find that contains a suitable stream.\n"); - mprint(" -multiprogram: Uses multiple programs from the same input stream.\n"); - mprint(" -datapid: Don't try to find out the stream for caption/teletext\n"); + mprint(" --multiprogram: Uses multiple programs from the same input stream.\n"); + mprint(" --datapid: Don't try to find out the stream for caption/teletext\n"); mprint(" data, just use this one instead.\n"); - mprint(" -datastreamtype: Instead of selecting the stream by its PID, select it\n"); + mprint(" --datastreamtype: Instead of selecting the stream by its PID, select it\n"); mprint(" by its type (pick the stream that has this type in\n"); mprint(" the PMT)\n"); - mprint(" -streamtype: Assume the data is of this type, don't autodetect. This\n"); - mprint(" parameter may be needed if -datapid or -datastreamtype\n"); + mprint(" --streamtype: Assume the data is of this type, don't autodetect. This\n"); + mprint(" parameter may be needed if --datapid or -datastreamtype\n"); mprint(" is used and CCExtractor cannot determine how to process\n"); mprint(" the stream. The value will usually be 2 (MPEG video) or\n"); mprint(" 6 (MPEG private data).\n"); - mprint(" -haup --hauppauge: If the video was recorder using a Hauppauge card, it\n"); + mprint(" --hauppauge: If the video was recorder using a Hauppauge card, it\n"); mprint(" might need special processing. This parameter will\n"); mprint(" force the special treatment.\n"); - mprint(" -mp4vidtrack: In MP4 files the closed caption data can be embedded in\n"); + mprint(" --mp4vidtrack: In MP4 files the closed caption data can be embedded in\n"); mprint(" the video track or in a dedicated CC track. If a\n"); mprint(" dedicated track is detected it will be processed instead\n"); mprint(" of the video track. If you need to force the video track\n"); mprint(" to be processed instead use this option.\n"); - mprint(" -noautotimeref: Some streams come with broadcast date information. When\n"); + mprint(" --no-autotimeref: Some streams come with broadcast date information. When\n"); mprint(" such data is available, CCExtractor will set its time\n"); mprint(" reference to the received data. Use this parameter if\n"); mprint(" you prefer your own reference. Note: Current this only\n"); mprint(" affects Teletext in timed transcript with -datets.\n"); - mprint(" --noscte20: Ignore SCTE-20 data if present.\n"); + mprint(" --no-scte20: Ignore SCTE-20 data if present.\n"); mprint(" --webvtt-create-css: Create a separate file for CSS instead of inline.\n"); - mprint(" -deblev: Enable debug so the calculated distance for each two\n"); + mprint(" --deblev: Enable debug so the calculated distance for each two\n"); mprint(" strings is displayed. The output includes both strings,\n"); mprint(" the calculated distance, the maximum allowed distance,\n"); mprint(" and whether the strings are ultimately considered \n"); mprint(" equivalent or not, i.e. the calculated distance is \n"); mprint(" less or equal than the max allowed..\n"); - mprint("-anvid --analyzevideo Analyze the video stream even if it's not used for\n"); + mprint(" --analyzevideo Analyze the video stream even if it's not used for\n"); mprint(" subtitles. This allows to provide video information.\n"); mprint(" --timestamp-map Enable the X-TIMESTAMP-MAP header for WebVTT (HLS)\n"); - mprint("Levenshtein distance:\n\n"); - mprint(" When processing teletext files CCExtractor tries to correct typos by\n"); - mprint(" comparing consecutive lines. If line N+1 is almost identical to line N except\n"); - mprint(" for minor changes (plus next characters) then it assumes that line N that a\n"); - mprint(" typo that was corrected in N+1. This is currently implemented in teletext\n"); - mprint(" because it's where samples files that could benefit from this were available.\n"); - mprint(" You can adjust, or disable, the algorithm settings with the following\n"); - mprint(" parameters.\n\n"); - mprint(" -nolevdist: Don't attempt to correct typos with Levenshtein distance.\n"); - mprint(" -levdistmincnt value: Minimum distance we always allow regardless\n"); + mprint("Levenshtein distance:\n"); + mprint(" --no-levdist: Don't attempt to correct typos with Levenshtein distance.\n"); + mprint(" --levdistmincnt value: Minimum distance we always allow regardless\n"); mprint(" of the length of the strings.Default 2. \n"); mprint(" This means that if the calculated distance \n"); mprint(" is 0,1 or 2, we consider the strings to be equivalent.\n"); - mprint(" -levdistmaxpct value: Maximum distance we allow, as a percentage of\n"); + mprint(" --levdistmaxpct value: Maximum distance we allow, as a percentage of\n"); mprint(" the shortest string length. Default 10%.\n"); mprint(" For example, consider a comparison of one string of \n"); mprint(" 30 characters and one of 60 characters. We want to \n"); @@ -596,31 +573,31 @@ void print_usage(void) mprint(" to 3 between the first 30 characters.\n"); mprint("\n"); mprint("Options that affect what kind of output will be produced:\n"); - mprint(" -chapters: (Experimental) Produces a chapter file from MP4 files.\n"); + mprint(" --chapters: (Experimental) Produces a chapter file from MP4 files.\n"); mprint(" Note that this must only be used with MP4 files,\n"); mprint(" for other files it will simply generate subtitles file.\n"); - mprint(" -bom: Append a BOM (Byte Order Mark) to output files.\n"); + mprint(" --bom: Append a BOM (Byte Order Mark) to output files.\n"); mprint(" Note that most text processing tools in linux will not\n"); mprint(" like BOM.\n"); - mprint(" -nobom: Do not append a BOM (Byte Order Mark) to output\n"); + mprint(" --no-bom: Do not append a BOM (Byte Order Mark) to output\n"); mprint(" files. Note that this may break files when using\n"); mprint(" Windows. This is the default in non-Windows builds.\n"); - mprint(" -unicode: Encode subtitles in Unicode instead of Latin-1.\n"); - mprint(" -utf8: Encode subtitles in UTF-8 (no longer needed.\n"); + mprint(" --unicode: Encode subtitles in Unicode instead of Latin-1.\n"); + mprint(" --utf8: Encode subtitles in UTF-8 (no longer needed.\n"); mprint(" because UTF-8 is now the default).\n"); - mprint(" -latin1: Encode subtitles in Latin-1\n"); - mprint(" -nofc --nofontcolor: For .srt/.sami/.vtt, don't add font color tags.\n"); - mprint(" --nohtmlescape: For .srt/.sami/.vtt, don't covert html unsafe character\n"); - mprint("-nots --notypesetting: For .srt/.sami/.vtt, don't add typesetting tags.\n"); - mprint(" -trim: Trim lines.\n"); - mprint(" -dc --defaultcolor: Select a different default color (instead of\n"); + mprint(" --latin1: Encode subtitles in Latin-1\n"); + mprint(" --no-fontcolor: For .srt/.sami/.vtt, don't add font color tags.\n"); + mprint(" --no-htmlescape: For .srt/.sami/.vtt, don't covert html unsafe character\n"); + mprint(" --no-typesetting: For .srt/.sami/.vtt, don't add typesetting tags.\n"); + mprint(" --trim: Trim lines.\n"); + mprint(" --defaultcolor: Select a different default color (instead of\n"); mprint(" white). This causes all output in .srt/.smi/.vtt\n"); mprint(" files to have a font tag, which makes the files\n"); mprint(" larger. Add the color you want in RGB, such as\n"); - mprint(" -dc #FF0000 for red.\n"); - mprint(" -sc --sentencecap: Sentence capitalization. Use if you hate\n"); + mprint(" --dc #FF0000 for red.\n"); + mprint(" --sentencecap: Sentence capitalization. Use if you hate\n"); mprint(" ALL CAPS in subtitles.\n"); - mprint(" --capfile -caf file: Add the contents of 'file' to the list of words\n"); + mprint(" --capfile file: Add the contents of 'file' to the list of words\n"); mprint(" that must be capitalized. For example, if file\n"); mprint(" is a plain text file that contains\n\n"); mprint(" Tony\n"); @@ -633,58 +610,58 @@ void print_usage(void) mprint("--profanity-file : Add the contents of to the list of words that.\n"); mprint(" must be censored. The content of , follows the\n"); mprint(" same syntax as for the capitalization file\n"); - mprint("-sbs --splitbysentence: Split output text so each frame contains a complete\n"); + mprint(" --splitbysentence: Split output text so each frame contains a complete\n"); mprint(" sentence. Timings are adjusted based on number of\n"); - mprint(" characters\n."); - mprint(" -unixts REF: For timed transcripts that have an absolute date\n"); + mprint(" characters\n"); + mprint(" --unixts REF: For timed transcripts that have an absolute date\n"); mprint(" instead of a timestamp relative to the file start), use\n"); mprint(" this time reference (UNIX timestamp). 0 => Use current\n"); mprint(" system time.\n"); mprint(" ccextractor will automatically switch to transport\n"); mprint(" stream UTC timestamps when available.\n"); - mprint(" -datets: In transcripts, write time as YYYYMMDDHHMMss,ms.\n"); - mprint(" -sects: In transcripts, write time as ss,ms\n"); - mprint(" -UCLA: Transcripts are generated with a specific format\n"); + mprint(" --datets: In transcripts, write time as YYYYMMDDHHMMss,ms.\n"); + mprint(" --sects: In transcripts, write time as ss,ms\n"); + mprint(" --UCLA: Transcripts are generated with a specific format\n"); mprint(" that is convenient for a specific project, feel\n"); mprint(" free to play with it but be aware that this format\n"); mprint(" is really live - don't rely on its output format\n"); mprint(" not changing between versions.\n"); - mprint(" -latrusmap Map Latin symbols to Cyrillic ones in special cases\n"); + mprint(" --latrusmap Map Latin symbols to Cyrillic ones in special cases\n"); mprint(" of Russian Teletext files (issue #1086)\n"); - mprint(" -xds: In timed transcripts, all XDS information will be saved\n"); + mprint(" --xds: In timed transcripts, all XDS information will be saved\n"); mprint(" to the output file.\n"); - mprint(" -lf: Use LF (UNIX) instead of CRLF (DOS, Windows) as line\n"); + mprint(" --lf: Use LF (UNIX) instead of CRLF (DOS, Windows) as line\n"); mprint(" terminator.\n"); - mprint(" -df: For MCC Files, force dropframe frame count.\n"); - mprint(" -autodash: Based on position on screen, attempt to determine\n"); + mprint(" --df: For MCC Files, force dropframe frame count.\n"); + mprint(" --autodash: Based on position on screen, attempt to determine\n"); mprint(" the different speakers and a dash (-) when each\n"); - mprint(" of them talks (.srt/.vtt only, -trim required).\n"); - mprint(" -xmltv mode: produce an XMLTV file containing the EPG data from\n"); + mprint(" of them talks (.srt/.vtt only, --trim required).\n"); + mprint(" --xmltv mode: produce an XMLTV file containing the EPG data from\n"); mprint(" the source TS file. Mode: 1 = full output\n"); mprint(" 2 = live output. 3 = both\n"); - mprint(" -xmltvliveinterval x: interval of x seconds between writing live mode xmltv output.\n"); - mprint("-xmltvoutputinterval x: interval of x seconds between writing full file xmltv output.\n"); - mprint(" -xmltvonlycurrent: Only print current events for xmltv output.\n"); - mprint(" -sem: Create a .sem file for each output file that is open\n"); + mprint(" --xmltvliveinterval x: interval of x seconds between writing live mode xmltv output.\n"); + mprint("--xmltvoutputinterval x: interval of x seconds between writing full file xmltv output.\n"); + mprint(" --xmltvonlycurrent: Only print current events for xmltv output.\n"); + mprint(" --sem: Create a .sem file for each output file that is open\n"); mprint(" and delete it on file close.\n"); - mprint(" -dvblang: For DVB subtitles, select which language's caption\n"); + mprint(" --dvblang: For DVB subtitles, select which language's caption\n"); mprint(" stream will be processed. e.g. 'eng' for English.\n"); mprint(" If there are multiple languages, only this specified\n"); mprint(" language stream will be processed (default).\n"); - mprint(" -ocrlang: Manually select the name of the Tesseract .traineddata\n"); + mprint(" --ocrlang: Manually select the name of the Tesseract .traineddata\n"); mprint(" file. Helpful if you want to OCR a caption stream of\n"); mprint(" one language with the data of another language.\n"); - mprint(" e.g. '-dvblang chs -ocrlang chi_tra' will decode the\n"); + mprint(" e.g. '-dvblang chs --ocrlang chi_tra' will decode the\n"); mprint(" Chinese (Simplified) caption stream but perform OCR\n"); mprint(" using the Chinese (Traditional) trained data\n"); mprint(" This option is also helpful when the traineddata file\n"); mprint(" has non standard names that don't follow ISO specs\n"); - mprint(" -quant mode: How to quantize the bitmap before passing it to tesseract\n"); + mprint(" --quant mode: How to quantize the bitmap before passing it to tesseract\n"); mprint(" for OCR'ing.\n"); mprint(" 0: Don't quantize at all.\n"); mprint(" 1: Use CCExtractor's internal function (default).\n"); mprint(" 2: Reduce distinct color count in image for faster results.\n"); - mprint(" -oem: Select the OEM mode for Tesseract.\n"); + mprint(" --oem: Select the OEM mode for Tesseract.\n"); mprint(" Available modes :\n"); mprint(" 0: OEM_TESSERACT_ONLY - the fastest mode.\n"); mprint(" 1: OEM_LSTM_ONLY - use LSTM algorithm for recognition.\n"); @@ -692,108 +669,89 @@ void print_usage(void) mprint(" Default value depends on the tesseract version linked :\n"); mprint(" Tesseract v3 : default mode is 0,\n"); mprint(" Tesseract v4 : default mode is 1.\n"); - mprint(" -mkvlang: For MKV subtitles, select which language's caption\n"); + mprint(" --mkvlang: For MKV subtitles, select which language's caption\n"); mprint(" stream will be processed. e.g. 'eng' for English.\n"); mprint(" Language codes can be either the 3 letters bibliographic\n"); mprint(" ISO-639-2 form (like \"fre\" for french) or a language\n"); mprint(" code followed by a dash and a country code for specialities\n"); mprint(" in languages (like \"fre-ca\" for Canadian French).\n"); - mprint(" -nospupngocr When processing DVB don't use the OCR to write the text as\n"); + mprint(" --no-spupngocr When processing DVB don't use the OCR to write the text as\n"); mprint(" comments in the XML file.\n"); - mprint(" -font: Specify the full path of the font that is to be used when\n"); + mprint(" --font: Specify the full path of the font that is to be used when\n"); mprint(" generating SPUPNG files. If not specified, you need to\n"); mprint(" have the default font installed (Helvetica for macOS, Calibri\n"); - mprint(" for Windows, and Noto for other operating systems at their\n)"); - mprint(" default location\n)"); - mprint(" -italics: Specify the full path of the italics font that is to be used when\n"); + mprint(" for Windows, and Noto for other operating systems at their)\n"); + mprint(" default location)\n"); + mprint(" --italics: Specify the full path of the italics font that is to be used when\n"); mprint(" generating SPUPNG files. If not specified, you need to\n"); mprint(" have the default font installed (Helvetica Oblique for macOS, Calibri Italic\n"); - mprint(" for Windows, and NotoSans Italic for other operating systems at their\n)"); - mprint(" default location\n)"); + mprint(" for Windows, and NotoSans Italic for other operating systems at their)\n"); + mprint(" default location)\n"); mprint("\n"); mprint("Options that affect how ccextractor reads and writes (buffering):\n"); - mprint(" -bi --bufferinput: Forces input buffering.\n"); - mprint(" -nobi -nobufferinput: Disables input buffering.\n"); - mprint(" -bs --buffersize val: Specify a size for reading, in bytes (suffix with K or\n"); + mprint(" --bufferinput: Forces input buffering.\n"); + mprint(" --no-bufferinput: Disables input buffering.\n"); + mprint(" --buffersize val: Specify a size for reading, in bytes (suffix with K or\n"); mprint(" or M for kilobytes and megabytes). Default is 16M.\n"); - mprint(" -koc: keep-output-close. If used then CCExtractor will close\n"); + mprint(" --koc: keep-output-close. If used then CCExtractor will close\n"); mprint(" the output file after writing each subtitle frame and\n"); mprint(" attempt to create it again when needed.\n"); - mprint(" -ff --forceflush: Flush the file buffer whenever content is written.\n"); + mprint(" --forceflush: Flush the file buffer whenever content is written.\n"); mprint("\n"); mprint("Options that affect the built-in 608 closed caption decoder:\n"); - mprint(" -dru: Direct Roll-Up. When in roll-up mode, write character by\n"); + mprint(" --dru: Direct Roll-Up. When in roll-up mode, write character by\n"); mprint(" character instead of line by line. Note that this\n"); mprint(" produces (much) larger files.\n"); - mprint(" -noru --norollup: If you hate the repeated lines caused by the roll-up\n"); + mprint(" --no-rollup: If you hate the repeated lines caused by the roll-up\n"); mprint(" emulation, you can have ccextractor write only one\n"); mprint(" line at a time, getting rid of these repeated lines.\n"); - mprint(" -ru1 / ru2 / ru3: roll-up captions can consist of 2, 3 or 4 visible\n"); + mprint(" --ru1 / ru2 / ru3: roll-up captions can consist of 2, 3 or 4 visible\n"); mprint(" lines at any time (the number of lines is part of\n"); mprint(" the transmission). If having 3 or 4 lines annoys\n"); - mprint(" you you can use -ru to force the decoder to always\n"); + mprint(" you you can use --ru to force the decoder to always\n"); mprint(" use 1, 2 or 3 lines. Note that 1 line is not\n"); mprint(" a real mode rollup mode, so CCExtractor does what\n"); mprint(" it can.\n"); - mprint(" In -ru1 the start timestamp is actually the timestamp\n"); + mprint(" In --ru1 the start timestamp is actually the timestamp\n"); mprint(" of the first character received which is possibly more\n"); mprint(" accurate.\n"); mprint("\n"); mprint("Options that affect timing:\n"); - mprint(" -delay ms: For srt/sami/webvtt, add this number of milliseconds to\n"); - mprint(" all times. For example, -delay 400 makes subtitles\n"); + mprint(" --delay ms: For srt/sami/webvtt, add this number of milliseconds to\n"); + mprint(" all times. For example, --delay 400 makes subtitles\n"); mprint(" appear 400ms late. You can also use negative numbers\n"); mprint(" to make subs appear early.\n"); - mprint("Notes on times: -startat and -endat times are used first, then -delay.\n"); - mprint("So if you use -srt -startat 3:00 -endat 5:00 -delay 120000, ccextractor will\n"); - mprint("generate a .srt file, with only data from 3:00 to 5:00 in the input file(s)\n"); - mprint("and then add that (huge) delay, which would make the final file start at\n"); - mprint("5:00 and end at 7:00.\n\n"); mprint("Options that affect what segment of the input file(s) to process:\n"); - mprint(" -startat time: Only write caption information that starts after the\n"); + mprint(" --startat time: Only write caption information that starts after the\n"); mprint(" given time.\n"); mprint(" Time can be seconds, MM:SS or HH:MM:SS.\n"); - mprint(" For example, -startat 3:00 means 'start writing from\n"); + mprint(" For example, --startat 3:00 means 'start writing from\n"); mprint(" minute 3.\n"); - mprint(" -endat time: Stop processing after the given time (same format as\n"); + mprint(" --endat time: Stop processing after the given time (same format as\n"); mprint(" -startat).\n"); - mprint(" The -startat and -endat options are honored in all\n"); + mprint(" The --startat and --endat options are honored in all\n"); mprint(" output formats. In all formats with timing information\n"); mprint(" the times are unchanged.\n"); - mprint("-scr --screenfuls num: Write 'num' screenfuls and terminate processing.\n\n"); + mprint(" --screenfuls num: Write 'num' screenfuls and terminate processing.\n\n"); mprint("Options that affect which codec is to be used have to be searched in input\n"); - mprint(" If codec type is not selected then first elementary stream suitable for \n" - " subtitle is selected, please consider -teletext -noteletext override this\n" - " option.\n" - " -codec dvbsub select the dvb subtitle from all elementary stream,\n" + mprint(" --codec dvbsub select the dvb subtitle from all elementary stream,\n" " if stream of dvb subtitle type is not found then \n" " nothing is selected and no subtitle is generated\n" - " -nocodec dvbsub ignore dvb subtitle and follow default behaviour\n" - " -codec teletext select the teletext subtitle from elementary stream\n" - " -nocodec teletext ignore teletext subtitle\n" - " NOTE: option given in form -foo=bar ,-foo = bar and --foo=bar are invalid\n" - " valid option are only in form -foo bar\n" - " nocodec and codec parameter must not be same if found to be same \n" - " then parameter of nocodec is ignored, this flag should be passed \n" - " once, more then one are not supported yet and last parameter would \n" - " taken in consideration\n"); + " --no-codec dvbsub ignore dvb subtitle and follow default behaviour\n" + " --codec teletext select the teletext subtitle from elementary stream\n" + " --no-codec teletext ignore teletext subtitle\n"); mprint("Adding start and end credits:\n"); - mprint(" CCExtractor can _try_ to add a custom message (for credits for example) at\n"); - mprint(" the start and end of the file, looking for a window where there are no\n"); - mprint(" captions. If there is no such window, then no text will be added.\n"); - mprint(" The start window must be between the times given and must have enough time\n"); - mprint(" to display the message for at least the specified time.\n"); mprint(" --startcreditstext txt: Write this text as start credits. If there are\n"); mprint(" several lines, separate them with the\n"); mprint(" characters \\n, for example Line1\\nLine 2.\n"); @@ -816,29 +774,29 @@ void print_usage(void) mprint("Options that affect debug data:\n"); - mprint(" -debug: Show lots of debugging output.\n"); - mprint(" -608: Print debug traces from the EIA-608 decoder.\n"); + mprint(" --debug: Show lots of debugging output.\n"); + mprint(" --608: Print debug traces from the EIA-608 decoder.\n"); mprint(" If you need to submit a bug report, please send\n"); mprint(" the output from this option.\n"); - mprint(" -708: Print debug information from the (currently\n"); + mprint(" --708: Print debug information from the (currently\n"); mprint(" in development) EIA-708 (DTV) decoder.\n"); - mprint(" -goppts: Enable lots of time stamp output.\n"); - mprint(" -xdsdebug: Enable XDS debug data (lots of it).\n"); - mprint(" -vides: Print debug info about the analysed elementary\n"); + mprint(" --goppts: Enable lots of time stamp output.\n"); + mprint(" --xdsdebug: Enable XDS debug data (lots of it).\n"); + mprint(" --vides: Print debug info about the analysed elementary\n"); mprint(" video stream.\n"); - mprint(" -cbraw: Print debug trace with the raw 608/708 data with\n"); + mprint(" --cbraw: Print debug trace with the raw 608/708 data with\n"); mprint(" time stamps.\n"); - mprint(" -nosync: Disable the syncing code. Only useful for debugging\n"); + mprint(" --no-sync: Disable the syncing code. Only useful for debugging\n"); mprint(" purposes.\n"); - mprint(" -fullbin: Disable the removal of trailing padding blocks\n"); + mprint(" --fullbin: Disable the removal of trailing padding blocks\n"); mprint(" when exporting to bin format. Only useful for\n"); mprint(" for debugging purposes.\n"); - mprint(" -parsedebug: Print debug info about the parsed container\n"); + mprint(" --parsedebug: Print debug info about the parsed container\n"); mprint(" file. (Only for TS/ASF files at the moment.)\n"); - mprint(" -parsePAT: Print Program Association Table dump.\n"); - mprint(" -parsePMT: Print Program Map Table dump.\n"); - mprint(" -dumpdef: Hex-dump defective TS packets.\n"); - mprint(" -investigate_packets: If no CC packets are detected based on the PMT, try\n"); + mprint(" --parsePAT: Print Program Association Table dump.\n"); + mprint(" --parsePMT: Print Program Map Table dump.\n"); + mprint(" --dumpdef: Hex-dump defective TS packets.\n"); + mprint(" --investigate-packets: If no CC packets are detected based on the PMT, try\n"); mprint(" to find data in all packets by scanning.\n"); #ifdef ENABLE_SHARING mprint(" -sharing-debug: Print extracted CC sharing service messages\n"); @@ -847,14 +805,14 @@ void print_usage(void) mprint("Teletext related options:\n"); - mprint(" -tpage page: Use this page for subtitles (if this parameter\n"); + mprint(" --tpage page: Use this page for subtitles (if this parameter\n"); mprint(" is not used, try to autodetect). In Spain the\n"); mprint(" page is always 888, may vary in other countries.\n"); - mprint(" -tverbose: Enable verbose mode in the teletext decoder.\n\n"); - mprint(" -teletext: Force teletext mode even if teletext is not detected.\n"); - mprint(" If used, you should also pass -datapid to specify\n"); + mprint(" --tverbose: Enable verbose mode in the teletext decoder.\n\n"); + mprint(" --teletext: Force teletext mode even if teletext is not detected.\n"); + mprint(" If used, you should also pass --datapid to specify\n"); mprint(" the stream ID you want to process.\n"); - mprint(" -noteletext: Disable teletext processing. This might be needed\n"); + mprint(" --no-teletext: Disable teletext processing. This might be needed\n"); mprint(" for video streams that have both teletext packets\n"); mprint(" and CEA-608/708 packets (if teletext is processed\n"); mprint(" then CEA-608/708 processing is disabled).\n"); @@ -862,7 +820,7 @@ void print_usage(void) mprint("Transcript customizing options:\n"); - mprint(" -customtxt format: Use the passed format to customize the (Timed) Transcript\n"); + mprint(" --customtxt format: Use the passed format to customize the (Timed) Transcript\n"); mprint(" output. The format must be like this: 1100100 (7 digits).\n"); mprint(" These indicate whether the next things should be\n"); mprint(" displayed or not in the (timed) transcript. They\n"); @@ -880,117 +838,164 @@ void print_usage(void) mprint(" 1111001 is the default setting for -ucla\n"); mprint(" Make sure you use this parameter after others that might\n"); mprint(" affect these settings (-out, -ucla, -xds, -txt, \n"); - mprint(" -ttxt ...)\n"); + mprint(" --ttxt ...)\n"); mprint("\n"); mprint("Communication with other programs and console output:\n"); - mprint(" --gui_mode_reports: Report progress and interesting events to stderr\n"); + mprint(" --gui-mode-reports: Report progress and interesting events to stderr\n"); mprint(" in a easy to parse format. This is intended to be\n"); mprint(" used by other programs. See docs directory for.\n"); mprint(" details.\n"); - mprint(" --no_progress_bar: Suppress the output of the progress bar\n"); - mprint(" -quiet: Don't write any message.\n"); + mprint(" --no-progress-bar: Suppress the output of the progress bar\n"); + mprint(" --quiet: Don't write any message.\n"); mprint("\n"); #ifdef ENABLE_SHARING mprint("Sharing extracted captions via TCP:\n"); - mprint(" -enable-sharing: Enables real-time sharing of extracted captions\n"); - mprint(" -sharing-url: Set url for sharing service in nanomsg format. Default: \"tcp://*:3269\"\n"); + mprint(" --enable-sharing: Enables real-time sharing of extracted captions\n"); + mprint(" --sharing-url: Set url for sharing service in nanomsg format. Default: \"tcp://*:3269\"\n"); mprint("\n"); mprint("CCTranslate application integration:\n"); - mprint(" -translate: Enable Translation tool and set target languages\n"); - mprint(" in csv format (e.g. -translate ru,fr,it\n"); - mprint(" -translate-auth: Set Translation Service authorization data to make translation possible\n"); + mprint(" --translate: Enable Translation tool and set target languages\n"); + mprint(" in csv format (e.g. --translate ru,fr,it\n"); + mprint(" --translate-auth: Set Translation Service authorization data to make translation possible\n"); mprint(" In case of Google Translate API - API Key\n"); #endif // ENABLE_SHARING - - mprint("Notes on the CEA-708 decoder: While it is starting to be useful, it's\n"); - mprint("a work in progress. A number of things don't work yet in the decoder\n"); - mprint("itself, and many of the auxiliary tools (case conversion to name one)\n"); - mprint("won't do anything yet. Feel free to submit samples that cause problems\n"); - mprint("and feature requests.\n"); - mprint("\n"); - mprint("Notes on spupng output format:\n"); - mprint("One .xml file is created per output field. A set of .png files are created in\n"); - mprint("a directory with the same base name as the corresponding .xml file(s), but with\n"); - mprint("a .d extension. Each .png file will contain an image representing one caption\n"); - mprint("and named subNNNN.png, starting with sub0000.png.\n"); - mprint("For example, the command:\n"); - mprint(" ccextractor -out=spupng input.mpg\n"); - mprint("will create the files:\n"); - mprint(" input.xml\n"); - mprint(" input.d/sub0000.png\n"); - mprint(" input.d/sub0001.png\n"); - mprint(" ...\n"); - mprint("The command:\n"); - mprint(" ccextractor -out=spupng -o /tmp/output -12 input.mpg\n"); - mprint("will create the files:\n"); - mprint(" /tmp/output_1.xml\n"); - mprint(" /tmp/output_1.d/sub0000.png\n"); - mprint(" /tmp/output_1.d/sub0001.png\n"); - mprint(" ...\n"); - mprint(" /tmp/output_2.xml\n"); - mprint(" /tmp/output_2.d/sub0000.png\n"); - mprint(" /tmp/output_2.d/sub0001.png\n"); - mprint(" ...\n"); - mprint("\n"); mprint("Burned-in subtitle extraction:\n"); - mprint(" -hardsubx : Enable the burned-in subtitle extraction subsystem.\n"); + mprint(" --hardsubx : Enable the burned-in subtitle extraction subsystem.\n"); mprint("\n"); - mprint(" NOTE: The following options will work only if -hardsubx is \n"); - mprint(" specified before them:-\n"); + mprint(" NOTE: This is needed to use the below burned-in \n"); + mprint(" subtitle extractor options\n"); mprint("\n"); - mprint(" -tickertext : Search for burned-in ticker text at the bottom of\n"); + mprint(" --tickertext : Search for burned-in ticker text at the bottom of\n"); mprint(" the screen.\n"); mprint("\n"); - mprint(" -ocr_mode : Set the OCR mode to either frame-wise, word-wise\n"); + mprint(" --ocr-mode : Set the OCR mode to either frame-wise, word-wise\n"); mprint(" or letter wise.\n"); - mprint(" e.g. -ocr_mode frame (default), -ocr_mode word, \n"); - mprint(" -ocr_mode letter\n"); + mprint(" e.g. --ocr-mode frame (default), --ocr-mode word, \n"); + mprint(" --ocr-mode letter\n"); mprint("\n"); - mprint(" -subcolor : Specify the color of the subtitles\n"); + mprint(" --subcolor : Specify the color of the subtitles\n"); mprint(" Possible values are in the set \n"); mprint(" {white,yellow,green,cyan,blue,magenta,red}.\n"); mprint(" Alternatively, a custom hue value between 1 and 360 \n"); mprint(" may also be specified.\n"); - mprint(" e.g. -subcolor white or -subcolor 270 (for violet).\n"); + mprint(" e.g. --subcolor white or --subcolor 270 (for violet).\n"); mprint(" Refer to an HSV color chart for values.\n"); mprint("\n"); - mprint(" -min_sub_duration : Specify the minimum duration that a subtitle line \n"); + mprint(" --min-sub-duration : Specify the minimum duration that a subtitle line \n"); mprint(" must exist on the screen.\n"); mprint(" The value is specified in seconds.\n"); mprint(" A lower value gives better results, but takes more \n"); mprint(" processing time.\n"); mprint(" The recommended value is 0.5 (default).\n"); - mprint(" e.g. -min_sub_duration 1.0 (for a duration of 1 second)\n"); + mprint(" e.g. --min-sub-duration 1.0 (for a duration of 1 second)\n"); mprint("\n"); - mprint(" -detect_italics : Specify whether italics are to be detected from the \n"); + mprint(" --detect-italics : Specify whether italics are to be detected from the \n"); mprint(" OCR text.\n"); mprint(" Italic detection automatically enforces the OCR mode \n"); mprint(" to be word-wise"); mprint("\n"); - mprint(" -conf_thresh : Specify the classifier confidence threshold between\n"); + mprint(" --conf-thresh : Specify the classifier confidence threshold between\n"); mprint(" 1 and 100.\n"); mprint(" Try and use a threshold which works for you if you get \n"); mprint(" a lot of garbage text.\n"); - mprint(" e.g. -conf_thresh 50\n"); + mprint(" e.g. --conf-thresh 50\n"); mprint("\n"); - mprint(" -whiteness_thresh : For white subtitles only, specify the luminance \n"); + mprint(" --whiteness-thresh : For white subtitles only, specify the luminance \n"); mprint(" threshold between 1 and 100\n"); mprint(" This threshold is content dependent, and adjusting\n"); mprint(" values may give you better results\n"); mprint(" Recommended values are in the range 80 to 100.\n"); mprint(" The default value is 95\n"); mprint("\n"); - mprint(" -hcc : This option will be used if the file should have both\n"); + mprint(" --hcc : This option will be used if the file should have both\n"); mprint(" closed captions and burned in subtitles\n"); mprint(" An example command for burned-in subtitle extraction is as follows:\n"); - mprint(" ccextractor video.mp4 -hardsubx -subcolor white -detect_italics \n"); - mprint(" -whiteness_thresh 90 -conf_thresh 60\n"); + mprint(" ccextractor video.mp4 --hardsubx -subcolor white --detect-italics \n"); + mprint(" --whiteness-thresh 90 --conf-thresh 60\n"); mprint("\n"); mprint("\n --version : Display current CCExtractor version and detailed information.\n"); + mprint("\n"); + mprint("Notes on File name related options:\n"); + mprint(" You can pass as many input files as you need. They will be processed in order.\n"); + mprint(" If a file name is suffixed by +, ccextractor will try to follow a numerical\n"); + mprint(" sequence. For example, DVD001.VOB+ means DVD001.VOB, DVD002.VOB and so on\n"); + mprint(" until there are no more files.\n"); + mprint(" Output will be one single file (either raw or srt). Use this if you made your\n"); + mprint(" recording in several cuts (to skip commercials for example) but you want one\n"); + mprint(" subtitle file with contiguous timing.\n"); + mprint("\n"); + mprint("Notes on Options that affect what will be processed:\n"); + mprint(" In general, if you want English subtitles you don't need to use these options\n"); + mprint(" as they are broadcast in field 1, channel 1. If you want the second language\n"); + mprint(" (usually Spanish) you may need to try -2, or -cc2, or both.\n"); + mprint("\n"); + mprint("Notes on Levenshtein distance:\n"); + mprint(" When processing teletext files CCExtractor tries to correct typos by\n"); + mprint(" comparing consecutive lines. If line N+1 is almost identical to line N except\n"); + mprint(" for minor changes (plus next characters) then it assumes that line N that a\n"); + mprint(" typo that was corrected in N+1. This is currently implemented in teletext\n"); + mprint(" because it's where samples files that could benefit from this were available.\n"); + mprint(" You can adjust, or disable, the algorithm settings with the following\n"); + mprint(" parameters.\n"); + mprint("\n"); + mprint("Notes on times:\n" + " --startat and --endat times are used first, then -delay.\n"); + mprint(" So if you use --srt -startat 3:00 --endat 5:00 --delay 120000, ccextractor will\n"); + mprint(" generate a .srt file, with only data from 3:00 to 5:00 in the input file(s)\n"); + mprint(" and then add that (huge) delay, which would make the final file start at\n"); + mprint(" 5:00 and end at 7:00.\n"); + mprint("\n"); + mprint("Notes on codec options:\n"); + mprint(" If codec type is not selected then first elementary stream suitable for \n" + " subtitle is selected, please consider --teletext -noteletext override this\n" + " option.\n"); + mprint(" no-codec and codec parameter must not be same if found to be same \n" + " then parameter of no-codec is ignored, this flag should be passed \n" + " once, more then one are not supported yet and last parameter would \n" + " taken in consideration\n"); + mprint("\n"); + mprint("Notes on adding credits:\n"); + mprint(" CCExtractor can _try_ to add a custom message (for credits for example) at\n"); + mprint(" the start and end of the file, looking for a window where there are no\n"); + mprint(" captions. If there is no such window, then no text will be added.\n"); + mprint(" The start window must be between the times given and must have enough time\n"); + mprint(" to display the message for at least the specified time.\n"); + mprint("\n"); + mprint("Notes on the CEA-708 decoder:\n" + " While it is starting to be useful, it's\n"); + mprint(" a work in progress. A number of things don't work yet in the decoder\n"); + mprint(" itself, and many of the auxiliary tools (case conversion to name one)\n"); + mprint(" won't do anything yet. Feel free to submit samples that cause problems\n"); + mprint(" and feature requests.\n"); + mprint("\n"); + mprint("Notes on spupng output format:\n"); + mprint(" One .xml file is created per output field. A set of .png files are created in\n"); + mprint(" a directory with the same base name as the corresponding .xml file(s), but with\n"); + mprint(" a .d extension. Each .png file will contain an image representing one caption\n"); + mprint(" and named subNNNN.png, starting with sub0000.png.\n"); + mprint(" For example, the command:\n"); + mprint(" ccextractor -out=spupng input.mpg\n"); + mprint(" will create the files:\n"); + mprint(" input.xml\n"); + mprint(" input.d/sub0000.png\n"); + mprint(" input.d/sub0001.png\n"); + mprint(" ...\n"); + mprint(" The command:\n"); + mprint(" ccextractor -out=spupng -o /tmp/output --12 input.mpg\n"); + mprint(" will create the files:\n"); + mprint(" /tmp/output_1.xml\n"); + mprint(" /tmp/output_1.d/sub0000.png\n"); + mprint(" /tmp/output_1.d/sub0001.png\n"); + mprint(" ...\n"); + mprint(" /tmp/output_2.xml\n"); + mprint(" /tmp/output_2.d/sub0000.png\n"); + mprint(" /tmp/output_2.d/sub0001.png\n"); + mprint(" ..."); + mprint("\n"); } unsigned char sha256_buf[16384]; @@ -1238,7 +1243,7 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) version(argv[0]); return EXIT_WITH_HELP; } - if (strcmp(argv[i], "-") == 0 || strcmp(argv[i], "-stdin") == 0) + if (strcmp(argv[i], "-") == 0 || strcmp(argv[i], "--stdin") == 0) { #ifdef WIN32 setmode(fileno(stdin), O_BINARY); @@ -1268,21 +1273,21 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) } #ifdef ENABLE_HARDSUBX - // Parse -hardsubx and related parameters - if (strcmp(argv[i], "-hardsubx") == 0) + // Parse --hardsubx and related parameters + if (strcmp(argv[i], "--hardsubx") == 0) { opt->hardsubx = 1; continue; } if (opt->hardsubx == 1) { - if (strcmp(argv[i], "-hcc") == 0) + if (strcmp(argv[i], "--hcc") == 0) { // if extraction of both burned in and non burned in subs opt->hardsubx_and_common = 1; continue; } - if (strcmp(argv[i], "-ocr_mode") == 0) + if (strcmp(argv[i], "--ocr-mode") == 0) { if (i < argc - 1) { @@ -1312,7 +1317,7 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) fatal(EXIT_MALFORMED_PARAMETER, "-ocr_mode has no argument.\nValid values are {frame,word,letter}\n"); } } - if (strcmp(argv[i], "-subcolor") == 0 || strcmp(argv[i], "-sub_color") == 0) + if (strcmp(argv[i], "--subcolor") == 0) { if (i < argc - 1) { @@ -1362,7 +1367,7 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) opt->hardsubx_hue = atof(str); if (opt->hardsubx_hue <= 0.0 || opt->hardsubx_hue > 360.0) { - fatal(EXIT_MALFORMED_PARAMETER, "-subcolor has either 0 or an invalid hue value supplied.\nIf you want to detect red subtitles, pass '-subcolor red' or a slightly higher hue value (e.g. 0.1)\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--subcolor has either 0 or an invalid hue value supplied.\nIf you want to detect red subtitles, pass '-subcolor red' or a slightly higher hue value (e.g. 0.1)\n"); } } @@ -1370,10 +1375,10 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) } else { - fatal(EXIT_MALFORMED_PARAMETER, "-subcolor has no argument.\nValid values are {white,yellow,green,cyan,blue,magenta,red} or a custom hue value between 0 and 360\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--subcolor has no argument.\nValid values are {white,yellow,green,cyan,blue,magenta,red} or a custom hue value between 0 and 360\n"); } } - if (strcmp(argv[i], "-min_sub_duration") == 0) + if (strcmp(argv[i], "--min-sub-duration") == 0) { if (i < argc - 1) { @@ -1384,22 +1389,22 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) opt->hardsubx_min_sub_duration = atof(str); if (opt->hardsubx_min_sub_duration == 0.0) { - fatal(EXIT_MALFORMED_PARAMETER, "-min_sub_duration has either 0 or an invalid value supplied\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--min-sub-duration has either 0 or an invalid value supplied\n"); } continue; } else { - fatal(EXIT_MALFORMED_PARAMETER, "-min_sub_duration has no argument.\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--min-sub-duration has no argument.\n"); } } - if (strcmp(argv[i], "-detect_italics") == 0) + if (strcmp(argv[i], "--detect-italics") == 0) { opt->hardsubx_detect_italics = 1; continue; } - if (strcmp(argv[i], "-conf_thresh") == 0) + if (strcmp(argv[i], "--conf-thresh") == 0) { if (i < argc - 1) { @@ -1410,17 +1415,17 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) opt->hardsubx_conf_thresh = atof(str); if (opt->hardsubx_conf_thresh <= 0.0 || opt->hardsubx_conf_thresh > 100.0) { - fatal(EXIT_MALFORMED_PARAMETER, "-conf_thresh has either 0 or an invalid value supplied\nValid values are in (0.0,100.0)\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--conf-thresh has either 0 or an invalid value supplied\nValid values are in (0.0,100.0)\n"); } continue; } else { - fatal(EXIT_MALFORMED_PARAMETER, "-conf_thresh has no argument.\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--conf-thresh has no argument.\n"); } } - if (strcmp(argv[i], "-whiteness_thresh") == 0 || strcmp(argv[i], "-lum_thresh") == 0) + if (strcmp(argv[i], "--whiteness-thresh") == 0 || strcmp(argv[i], "--lum-thresh") == 0) { if (i < argc - 1) { @@ -1431,40 +1436,40 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) opt->hardsubx_lum_thresh = atof(str); if (opt->hardsubx_lum_thresh <= 0.0 || opt->hardsubx_conf_thresh > 100.0) { - fatal(EXIT_MALFORMED_PARAMETER, "-whiteness_thresh has either 0 or an invalid value supplied\nValid values are in (0.0,100.0)\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--whiteness-thresh has either 0 or an invalid value supplied\nValid values are in (0.0,100.0)\n"); } continue; } else { - fatal(EXIT_MALFORMED_PARAMETER, "-whiteness_thresh has no argument.\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--whiteness-thresh has no argument.\n"); } } } #endif // ENABLE_HARDSUBX - if (strcmp(argv[i], "-chapters") == 0) + if (strcmp(argv[i], "--chapters") == 0) { opt->extract_chapters = 1; continue; } - if (strcmp(argv[i], "-bi") == 0 || strcmp(argv[i], "--bufferinput") == 0) + if (strcmp(argv[i], "--bufferinput") == 0) { opt->buffer_input = 1; continue; } - if (strcmp(argv[i], "-nobi") == 0 || strcmp(argv[i], "--nobufferinput") == 0) + if (strcmp(argv[i], "--no-bufferinput") == 0) { opt->buffer_input = 0; continue; } - if (strcmp(argv[i], "-koc") == 0) + if (strcmp(argv[i], "--koc") == 0) { opt->keep_output_closed = 1; continue; } - if (strcmp(argv[i], "-ff") == 0 || strcmp(argv[i], "--forceflush") == 0) + if (strcmp(argv[i], "--forceflush") == 0) { opt->force_flush = 1; continue; @@ -1474,7 +1479,7 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) opt->append_mode = 1; continue; } - if (strcmp(argv[i], "-bs") == 0 || strcmp(argv[i], "--buffersize") == 0) + if (strcmp(argv[i], "--buffersize") == 0) { if (i < argc - 1) { @@ -1493,69 +1498,69 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) fatal(EXIT_MALFORMED_PARAMETER, "--buffersize has no argument.\n"); } } - if (strcmp(argv[i], "-dru") == 0) + if (strcmp(argv[i], "--dru") == 0) { opt->settings_608.direct_rollup = 1; continue; } - if (strcmp(argv[i], "-nofc") == 0 || strcmp(argv[i], "--nofontcolor") == 0) + if (strcmp(argv[i], "--no-fontcolor") == 0) { opt->nofontcolor = 1; continue; } - if (strcmp(argv[i], "--nohtmlescape") == 0) + if (strcmp(argv[i], "--no-htmlescape") == 0) { opt->nohtmlescape = 1; continue; } - if (strcmp(argv[i], "-bom") == 0) + if (strcmp(argv[i], "--bom") == 0) { opt->enc_cfg.no_bom = 0; continue; } - if (strcmp(argv[i], "-nobom") == 0) + if (strcmp(argv[i], "--no-bom") == 0) { opt->enc_cfg.no_bom = 1; continue; } - if (strcmp(argv[i], "-sem") == 0) + if (strcmp(argv[i], "--sem") == 0) { opt->enc_cfg.with_semaphore = 1; continue; } - if (strcmp(argv[i], "-nots") == 0 || strcmp(argv[i], "--notypesetting") == 0) + if (strcmp(argv[i], "--no-typesetting") == 0) { opt->notypesetting = 1; continue; } - if (strcmp(argv[i], "--timestamp-map") == 0 || strcmp(argv[i], "-tm") == 0) + if (strcmp(argv[i], "--timestamp-map") == 0) { opt->timestamp_map = 1; continue; } /* Input file formats */ - if (strcmp(argv[i], "-es") == 0 || - strcmp(argv[i], "-ts") == 0 || - strcmp(argv[i], "-ps") == 0 || - strcmp(argv[i], "-asf") == 0 || - strcmp(argv[i], "-wtv") == 0 || - strcmp(argv[i], "-mp4") == 0 || - strcmp(argv[i], "-mkv") == 0 || + if (strcmp(argv[i], "--es") == 0 || + strcmp(argv[i], "--ts") == 0 || + strcmp(argv[i], "--ps") == 0 || + strcmp(argv[i], "--asf") == 0 || + strcmp(argv[i], "--wtv") == 0 || + strcmp(argv[i], "--mp4") == 0 || + strcmp(argv[i], "--mkv") == 0 || strcmp(argv[i], "--dvr-ms") == 0) { set_input_format(opt, argv[i]); continue; } - if (strncmp(argv[i], "-in=", 4) == 0) + if (strncmp(argv[i], "--in=", 5) == 0) { - set_input_format(opt, argv[i] + 4); + set_input_format(opt, argv[i] + 5); continue; } /*user specified subtitle to be selected */ - if (strcmp(argv[i], "-codec") == 0) + if (strcmp(argv[i], "--codec") == 0) { if (i < argc - 1) { @@ -1578,12 +1583,12 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) } else { - fatal(EXIT_MALFORMED_PARAMETER, "-codec has no argument.\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--codec has no argument.\n"); } } /*user specified subtitle to be selected */ - if (strcmp(argv[i], "-nocodec") == 0) + if (strcmp(argv[i], "--no-codec") == 0) { if (i < argc - 1) { @@ -1599,18 +1604,18 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) } else { - fatal(EXIT_MALFORMED_PARAMETER, "Invalid option for nocodec.\n"); + fatal(EXIT_MALFORMED_PARAMETER, "Invalid option for no-codec.\n"); } continue; } else { - fatal(EXIT_MALFORMED_PARAMETER, "-nocodec has no argument.\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--no-codec has no argument.\n"); } } - if (strcmp(argv[i], "-dvblang") == 0) + if (strcmp(argv[i], "--dvblang") == 0) { if (i < argc - 1) { @@ -1627,11 +1632,11 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) } else { - fatal(EXIT_MALFORMED_PARAMETER, "-dvblang has no argument.\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--dvblang has no argument.\n"); } } - if (strcmp(argv[i], "-ocrlang") == 0) + if (strcmp(argv[i], "--ocrlang") == 0) { if (i++ < argc - 1) { @@ -1640,10 +1645,10 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) } else { - fatal(EXIT_MALFORMED_PARAMETER, "-ocrlang has no argument.\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--ocrlang has no argument.\n"); } } - if (strcmp(argv[i], "-quant") == 0) + if (strcmp(argv[i], "--quant") == 0) { if (i < argc - 1) { @@ -1653,15 +1658,15 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) } else { - fatal(EXIT_MALFORMED_PARAMETER, "-quant has no argument.\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--quant has no argument.\n"); } } - if (strcmp(argv[i], "-nospupngocr") == 0) + if (strcmp(argv[i], "--no-spupngocr") == 0) { opt->enc_cfg.nospupngocr = 1; continue; } - if (strcmp(argv[i], "-oem") == 0) + if (strcmp(argv[i], "--oem") == 0) { if (i < argc - 1) { @@ -1672,17 +1677,17 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) opt->ocr_oem = atoi(str); if (opt->ocr_oem < 0 || opt->ocr_oem > 2) { - fatal(EXIT_MALFORMED_PARAMETER, "-oem must be 0, 1 or 2\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--oem must be 0, 1 or 2\n"); } continue; } else { - fatal(EXIT_MALFORMED_PARAMETER, "-oem has no argument.\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--oem has no argument.\n"); } } - if (strcmp(argv[i], "-mkvlang") == 0) + if (strcmp(argv[i], "--mkvlang") == 0) { if (i < argc - 1) { @@ -1696,24 +1701,24 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) } else { - fatal(EXIT_MALFORMED_PARAMETER, "-mkvlang has no argument.\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--mkvlang has no argument.\n"); } } /* Output file formats */ - if (strcmp(argv[i], "-srt") == 0 || - strcmp(argv[i], "-mcc") == 0 || strcmp(argv[i], "-dvdraw") == 0 || - strcmp(argv[i], "-smi") == 0 || strcmp(argv[i], "-sami") == 0 || - strcmp(argv[i], "-txt") == 0 || strcmp(argv[i], "--transcript") == 0 || - strcmp(argv[i], "-ttxt") == 0 || strcmp(argv[i], "--timedtranscript") == 0 || - strcmp(argv[i], "-webvtt") == 0 || strcmp(argv[i], "-null") == 0) + if (strcmp(argv[i], "--srt") == 0 || + strcmp(argv[i], "--mcc") == 0 || strcmp(argv[i], "--dvdraw") == 0 || + strcmp(argv[i], "--smi") == 0 || strcmp(argv[i], "--sami") == 0 || + strcmp(argv[i], "--txt") == 0 || strcmp(argv[i], "--transcript") == 0 || + strcmp(argv[i], "--ttxt") == 0 || strcmp(argv[i], "--timedtranscript") == 0 || + strcmp(argv[i], "--webvtt") == 0 || strcmp(argv[i], "--null") == 0) { set_output_format(opt, argv[i]); continue; } - if (strncmp(argv[i], "-out=", 5) == 0) + if (strncmp(argv[i], "--out=", 6) == 0) { - set_output_format(opt, argv[i] + 5); + set_output_format(opt, argv[i] + 6); continue; } @@ -1842,38 +1847,32 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) } /* More stuff */ - if (strcmp(argv[i], "-ve") == 0 || strcmp(argv[i], "--videoedited") == 0) + if (strcmp(argv[i], "--videoedited") == 0) { opt->binary_concat = 0; continue; } - if (strcmp(argv[i], "-12") == 0) - { - opt->is_608_enabled = 1; - opt->extract = 12; - continue; - } - if (strcmp(argv[i], "-gt") == 0 || strcmp(argv[i], "--goptime") == 0) + if (strcmp(argv[i], "--goptime") == 0) { opt->use_gop_as_pts = 1; continue; } - if (strcmp(argv[i], "-nogt") == 0 || strcmp(argv[i], "--nogoptime") == 0) + if (strcmp(argv[i], "--no-goptime") == 0) { opt->use_gop_as_pts = -1; // Don't use even if we would want to continue; } - if (strcmp(argv[i], "-fp") == 0 || strcmp(argv[i], "--fixpadding") == 0) + if (strcmp(argv[i], "--fixpadding") == 0) { opt->fix_padding = 1; continue; } - if (strcmp(argv[i], "-90090") == 0) + if (strcmp(argv[i], "--90090") == 0) { MPEG_CLOCK_FREQ = 90090; continue; } - if (strcmp(argv[i], "--noscte20") == 0) + if (strcmp(argv[i], "--no-scte20") == 0) { opt->noscte20 = 1; continue; @@ -1883,34 +1882,34 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) opt->webvtt_create_css = 1; continue; } - if (strcmp(argv[i], "-noru") == 0 || strcmp(argv[i], "--norollup") == 0) + if (strcmp(argv[i], "--no-rollup") == 0) { opt->no_rollup = 1; opt->settings_608.no_rollup = 1; opt->settings_dtvcc.no_rollup = 1; continue; } - if (strcmp(argv[i], "-ru1") == 0) + if (strcmp(argv[i], "--ru1") == 0) { opt->settings_608.force_rollup = 1; continue; } - if (strcmp(argv[i], "-ru2") == 0) + if (strcmp(argv[i], "--ru2") == 0) { opt->settings_608.force_rollup = 2; continue; } - if (strcmp(argv[i], "-ru3") == 0) + if (strcmp(argv[i], "--ru3") == 0) { opt->settings_608.force_rollup = 3; continue; } - if (strcmp(argv[i], "-trim") == 0) + if (strcmp(argv[i], "--trim") == 0) { opt->enc_cfg.trim_subs = 1; continue; } - if (strcmp(argv[i], "-outinterval") == 0) + if (strcmp(argv[i], "--outinterval") == 0) { if (i < argc - 1) { @@ -1923,35 +1922,35 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) fatal(EXIT_MALFORMED_PARAMETER, "-outinterval has no argument.\n"); } } - if (strcmp(argv[i], "--segmentonkeyonly") == 0 || strcmp(argv[i], "-key") == 0) + if (strcmp(argv[i], "--segmentonkeyonly") == 0) { opt->segment_on_key_frames_only = 1; opt->analyze_video_stream = 1; continue; } - if (strcmp(argv[i], "--gui_mode_reports") == 0) + if (strcmp(argv[i], "--gui-mode-reports") == 0) { opt->gui_mode_reports = 1; continue; } - if (strcmp(argv[i], "--no_progress_bar") == 0) + if (strcmp(argv[i], "--no-progress-bar") == 0) { opt->no_progress_bar = 1; continue; } - if (strcmp(argv[i], "--splitbysentence") == 0 || strcmp(argv[i], "-sbs") == 0) + if (strcmp(argv[i], "--splitbysentence") == 0) { opt->enc_cfg.splitbysentence = 1; continue; } - if (strcmp(argv[i], "--sentencecap") == 0 || strcmp(argv[i], "-sc") == 0) + if (strcmp(argv[i], "--sentencecap") == 0) { opt->enc_cfg.sentence_cap = 1; continue; } - if ((strcmp(argv[i], "--capfile") == 0 || strcmp(argv[i], "-caf") == 0) && i < argc - 1) + if (strcmp(argv[i], "--capfile") == 0 && i < argc - 1) { opt->enc_cfg.sentence_cap = 1; opt->sentence_cap_file = argv[i + 1]; @@ -1975,7 +1974,7 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) continue; } - if (strcmp(argv[i], "--program-number") == 0 || strcmp(argv[i], "-pn") == 0) + if (strcmp(argv[i], "--program-number") == 0) { if (i < argc - 1 && isanumber(argv[i + 1])) { @@ -1990,12 +1989,12 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) continue; } } - if (strcmp(argv[i], "-autoprogram") == 0) + if (strcmp(argv[i], "--autoprogram") == 0) { opt->demux_cfg.ts_autoprogram = 1; continue; } - if (strcmp(argv[i], "-multiprogram") == 0) + if (strcmp(argv[i], "--multiprogram") == 0) { opt->multiprogram = 1; opt->demux_cfg.ts_allprogram = CCX_TRUE; @@ -2015,7 +2014,7 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) continue; } } - if (strcmp(argv[i], "--defaultcolor") == 0 || strcmp(argv[i], "-dc") == 0) + if (strcmp(argv[i], "--defaultcolor") == 0) { if (i < argc - 1) { @@ -2033,23 +2032,23 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) fatal(EXIT_MALFORMED_PARAMETER, "--defaultcolor has no argument.\n"); } } - if (strcmp(argv[i], "-delay") == 0) + if (strcmp(argv[i], "--delay") == 0) { if (i < argc - 1) { i++; if (parsedelay(opt, argv[i])) { - fatal(EXIT_MALFORMED_PARAMETER, "-delay only accept integers (such as -300 or 300)\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--delay only accept integers (such as --300 or 300)\n"); } continue; } else { - fatal(EXIT_MALFORMED_PARAMETER, "-delay has no argument.\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--delay has no argument.\n"); } } - if (strcmp(argv[i], "-scr") == 0 || strcmp(argv[i], "--screenfuls") == 0) + if (strcmp(argv[i], "--screenfuls") == 0) { if (i < argc - 1) { @@ -2066,111 +2065,118 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) fatal(EXIT_MALFORMED_PARAMETER, "--screenfuls has no argument.\n"); } } - if (strcmp(argv[i], "-startat") == 0) + if (strcmp(argv[i], "--startat") == 0) { if (i < argc - 1) { i++; if (stringztoms(argv[i], &opt->extraction_start) == -1) { - fatal(EXIT_MALFORMED_PARAMETER, "-startat only accepts SS, MM:SS or HH:MM:SS\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--startat only accepts SS, MM:SS or HH:MM:SS\n"); } continue; } else { - fatal(EXIT_MALFORMED_PARAMETER, "-startat has no argument.\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--startat has no argument.\n"); } } - if (strcmp(argv[i], "-endat") == 0) + if (strcmp(argv[i], "--endat") == 0) { if (i < argc - 1) { i++; if (stringztoms(argv[i], &opt->extraction_end) == -1) { - fatal(EXIT_MALFORMED_PARAMETER, "-endat only accepts SS, MM:SS or HH:MM:SS\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--endat only accepts SS, MM:SS or HH:MM:SS\n"); } continue; } else { - fatal(EXIT_MALFORMED_PARAMETER, "-endat has no argument.\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--endat has no argument.\n"); } } - if (strcmp(argv[i], "-1") == 0) + if (strcmp(argv[i], "--output-field") == 0) { - opt->is_608_enabled = 1; - opt->extract = 1; - continue; - } - if (strcmp(argv[i], "-2") == 0) - { - opt->is_608_enabled = 1; - opt->extract = 2; - continue; + if (i < argc - 1) + { + i++; + opt->extract = strcmp(argv[i], "both") == 0 ? 12 : atoi_hex(argv[i]); + if (opt->extract != 1 && opt->extract != 2 && opt->extract != 12) + { + fatal(EXIT_MALFORMED_PARAMETER, "--output-field only accepts 1 or 2 or both.\n"); + } + opt->is_608_enabled = 1; + continue; + } + else + { + fatal(EXIT_MALFORMED_PARAMETER, "--output-field has no argument.\n"); + } } - if (strcmp(argv[i], "-cc2") == 0 || strcmp(argv[i], "-CC2") == 0) + + if (strcmp(argv[i], "--cc2") == 0 || strcmp(argv[i], "--CC2") == 0) { opt->cc_channel = 2; continue; } - if (strcmp(argv[i], "-stdout") == 0) + if (strcmp(argv[i], "--stdout") == 0) { - if (opt->messages_target == 1) // Only change this if still stdout. -quiet could set it to 0 for example + if (opt->messages_target == 1) // Only change this if still stdout. --quiet could set it to 0 for example { opt->messages_target = 2; // stderr } opt->cc_to_stdout = 1; continue; } - if (strcmp(argv[i], "-pesheader") == 0) + if (strcmp(argv[i], "--pesheader") == 0) { opt->pes_header_to_stdout = 1; continue; } - if (strcmp(argv[i], "-debugdvbsub") == 0) + if (strcmp(argv[i], "--debugdvbsub") == 0) { opt->debug_mask |= CCX_DMT_DVB; continue; } - if (strcmp(argv[i], "-ignoreptsjumps") == 0) + if (strcmp(argv[i], "--ignoreptsjumps") == 0) { opt->ignore_pts_jumps = 1; continue; } - // -ignoreptsjumps counterpart - if (strcmp(argv[i], "-fixptsjumps") == 0) + // --ignoreptsjumps counterpart + if (strcmp(argv[i], "--fixptsjumps") == 0) { opt->ignore_pts_jumps = 0; continue; } - if (strcmp(argv[i], "-quiet") == 0) + if (strcmp(argv[i], "--quiet") == 0) { opt->messages_target = 0; continue; } - if (strcmp(argv[i], "-debug") == 0) + if (strcmp(argv[i], "--debug") == 0) { opt->debug_mask |= CCX_DMT_VERBOSE; continue; } - if (strcmp(argv[i], "-608") == 0) + if (strcmp(argv[i], "--608") == 0) { opt->debug_mask |= CCX_DMT_DECODER_608; continue; } - if (strcmp(argv[i], "-deblev") == 0) + if (strcmp(argv[i], "--deblev") == 0) { opt->debug_mask |= CCX_DMT_LEVENSHTEIN; continue; } - if (strcmp(argv[i], "-nolevdist") == 0) + if (strcmp(argv[i], "--no-levdist") == 0) { opt->dolevdist = 0; continue; } - if (strcmp(argv[i], "-levdistmincnt") == 0) + if (strcmp(argv[i], "--levdistmincnt") == 0) { if (i < argc - 1) { @@ -2180,10 +2186,10 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) } else { - fatal(EXIT_MALFORMED_PARAMETER, "-levdistmincnt has no argument.\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--levdistmincnt has no argument.\n"); } } - if (strcmp(argv[i], "-levdistmaxpct") == 0) + if (strcmp(argv[i], "--levdistmaxpct") == 0) { if (i < argc - 1) { @@ -2193,10 +2199,10 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) } else { - fatal(EXIT_MALFORMED_PARAMETER, "-levdistmaxpct has no argument.\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--levdistmaxpct has no argument.\n"); } } - if (strcmp(argv[i], "-708") == 0) + if (strcmp(argv[i], "--708") == 0) { opt->debug_mask |= CCX_DMT_708; #ifndef DISABLE_RUST @@ -2204,133 +2210,133 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) #endif continue; } - if (strcmp(argv[i], "-goppts") == 0) + if (strcmp(argv[i], "--goppts") == 0) { opt->debug_mask |= CCX_DMT_TIME; continue; } - if (strcmp(argv[i], "-vides") == 0) + if (strcmp(argv[i], "--vides") == 0) { opt->debug_mask |= CCX_DMT_VIDES; opt->analyze_video_stream = 1; continue; } - if (strcmp(argv[i], "-anvid") == 0 || strcmp(argv[i], "--analyzevideo") == 0) + if (strcmp(argv[i], "--analyzevideo") == 0) { opt->analyze_video_stream = 1; continue; } - if (strcmp(argv[i], "-xds") == 0) + if (strcmp(argv[i], "--xds") == 0) { - // XDS can be set regardless of -UCLA (isFinal) usage. + // XDS can be set regardless of --UCLA (isFinal) usage. opt->transcript_settings.xds = 1; continue; } - if (strcmp(argv[i], "-xdsdebug") == 0) + if (strcmp(argv[i], "--xdsdebug") == 0) { opt->transcript_settings.xds = 1; opt->debug_mask |= CCX_DMT_DECODER_XDS; continue; } - if (strcmp(argv[i], "-parsedebug") == 0) + if (strcmp(argv[i], "--parsedebug") == 0) { opt->debug_mask |= CCX_DMT_PARSE; continue; } - if (strcmp(argv[i], "-parsePAT") == 0 || strcmp(argv[i], "-parsepat") == 0) + if (strcmp(argv[i], "--parsePAT") == 0 || strcmp(argv[i], "--parsepat") == 0) { opt->debug_mask |= CCX_DMT_PAT; continue; } - if (strcmp(argv[i], "-parsePMT") == 0 || strcmp(argv[i], "-parsepmt") == 0) + if (strcmp(argv[i], "--parsePMT") == 0 || strcmp(argv[i], "--parsepmt") == 0) { opt->debug_mask |= CCX_DMT_PMT; continue; } - if (strcmp(argv[i], "-dumpdef") == 0) + if (strcmp(argv[i], "--dumpdef") == 0) { opt->debug_mask |= CCX_DMT_DUMPDEF; continue; } - if (strcmp(argv[i], "-investigate_packets") == 0) + if (strcmp(argv[i], "--investigate-packets") == 0) { opt->investigate_packets = 1; continue; } - if (strcmp(argv[i], "-cbraw") == 0) + if (strcmp(argv[i], "--cbraw") == 0) { opt->debug_mask |= CCX_DMT_CBRAW; continue; } - if (strcmp(argv[i], "-tverbose") == 0) + if (strcmp(argv[i], "--tverbose") == 0) { opt->debug_mask |= CCX_DMT_TELETEXT; tlt_config.verbose = 1; continue; } #ifdef ENABLE_SHARING - if (strcmp(argv[i], "-sharing-debug") == 0) + if (strcmp(argv[i], "--sharing-debug") == 0) { opt->debug_mask |= CCX_DMT_SHARE; continue; } #endif // ENABLE_SHARING - if (strcmp(argv[i], "-fullbin") == 0) + if (strcmp(argv[i], "--fullbin") == 0) { opt->fullbin = 1; continue; } - if (strcmp(argv[i], "-nosync") == 0) + if (strcmp(argv[i], "--no-sync") == 0) { opt->nosync = 1; continue; } - if (strcmp(argv[i], "-haup") == 0 || strcmp(argv[i], "--hauppauge") == 0) + if (strcmp(argv[i], "--hauppauge") == 0) { opt->hauppauge_mode = 1; continue; } - if (strcmp(argv[i], "-mp4vidtrack") == 0) + if (strcmp(argv[i], "--mp4vidtrack") == 0) { opt->mp4vidtrack = 1; continue; } - if (strstr(argv[i], "-unicode") != NULL) + if (strstr(argv[i], "--unicode") != NULL) { opt->enc_cfg.encoding = CCX_ENC_UNICODE; continue; } - if (strstr(argv[i], "-utf8") != NULL) + if (strstr(argv[i], "--utf8") != NULL) { opt->enc_cfg.encoding = CCX_ENC_UTF_8; continue; } - if (strstr(argv[i], "-latin1") != NULL) + if (strstr(argv[i], "--latin1") != NULL) { opt->enc_cfg.encoding = CCX_ENC_LATIN_1; continue; } - if (strcmp(argv[i], "-poc") == 0 || strcmp(argv[i], "--usepicorder") == 0) + if (strcmp(argv[i], "--usepicorder") == 0) { opt->usepicorder = 1; continue; } - if (strstr(argv[i], "-myth") != NULL) + if (strstr(argv[i], "--myth") != NULL) { opt->auto_myth = 1; continue; } - if (strstr(argv[i], "-nomyth") != NULL) + if (strstr(argv[i], "--no-myth") != NULL) { opt->auto_myth = 0; continue; } - if (strstr(argv[i], "-wtvconvertfix") != NULL) + if (strstr(argv[i], "--wtvconvertfix") != NULL) { opt->wtvconvertfix = 1; continue; } - if (strstr(argv[i], "-wtvmpeg2") != NULL) + if (strstr(argv[i], "--wtvmpeg2") != NULL) { opt->wtvmpeg2 = 1; continue; @@ -2348,7 +2354,7 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) fatal(EXIT_MALFORMED_PARAMETER, "-o has no argument.\n"); } } - if (strcmp(argv[i], "-svc") == 0 || strcmp(argv[i], "--service") == 0) + if (strcmp(argv[i], "--service") == 0) { if (i < argc - 1) { @@ -2362,7 +2368,7 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) fatal(EXIT_MALFORMED_PARAMETER, "--service has no argument.\n"); } } - if (strcmp(argv[i], "-datapid") == 0) + if (strcmp(argv[i], "--datapid") == 0) { if (i < argc - 1) { @@ -2373,10 +2379,10 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) } else { - fatal(EXIT_MALFORMED_PARAMETER, "-datapid has no argument.\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--datapid has no argument.\n"); } } - if (strcmp(argv[i], "-datastreamtype") == 0) + if (strcmp(argv[i], "--datastreamtype") == 0) { if (i < argc - 1) { @@ -2386,10 +2392,10 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) } else { - fatal(EXIT_MALFORMED_PARAMETER, "-datastreamtype has no argument.\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--datastreamtype has no argument.\n"); } } - if (strcmp(argv[i], "-streamtype") == 0) + if (strcmp(argv[i], "--streamtype") == 0) { if (i < argc - 1) { @@ -2399,12 +2405,12 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) } else { - fatal(EXIT_MALFORMED_PARAMETER, "-streamtype has no argument.\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--streamtype has no argument.\n"); } } /* Teletext stuff */ - if (strcmp(argv[i], "-tpage") == 0) + if (strcmp(argv[i], "--tpage") == 0) { if (i < argc - 1) { @@ -2415,12 +2421,12 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) } else { - fatal(EXIT_MALFORMED_PARAMETER, "-tpage has no argument.\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--tpage has no argument.\n"); } } /* Red Hen/ UCLA Specific stuff */ - if (strcmp(argv[i], "-UCLA") == 0 || strcmp(argv[i], "-ucla") == 0) + if (strcmp(argv[i], "--UCLA") == 0 || strcmp(argv[i], "--ucla") == 0) { opt->ucla = 1; opt->millis_separator = '.'; @@ -2436,37 +2442,37 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) } continue; } - if (strcmp(argv[i], "-latrusmap") == 0) + if (strcmp(argv[i], "--latrusmap") == 0) { tlt_config.latrusmap = 1; continue; } - if (strcmp(argv[i], "-tickertext") == 0 || strcmp(argv[i], "-tickertape") == 0) + if (strcmp(argv[i], "--tickertext") == 0 || strcmp(argv[i], "--tickertape") == 0) { opt->tickertext = 1; continue; } - if (strcmp(argv[i], "-lf") == 0 || strcmp(argv[i], "-LF") == 0) + if (strcmp(argv[i], "--lf") == 0 || strcmp(argv[i], "--LF") == 0) { opt->enc_cfg.line_terminator_lf = 1; continue; } - if (strcmp(argv[i], "-df") == 0 || strcmp(argv[i], "-DF") == 0) + if (strcmp(argv[i], "--df") == 0 || strcmp(argv[i], "--DF") == 0) { opt->enc_cfg.force_dropframe = 1; continue; } - if (strcmp(argv[i], "-noautotimeref") == 0) + if (strcmp(argv[i], "--no-autotimeref") == 0) { opt->noautotimeref = 1; continue; } - if (strcmp(argv[i], "-autodash") == 0 || strcmp(argv[i], "-sem") == 0) + if (strcmp(argv[i], "--autodash") == 0 || strcmp(argv[i], "--sem") == 0) { opt->enc_cfg.autodash = 1; continue; } - if (strcmp(argv[i], "-xmltv") == 0) + if (strcmp(argv[i], "--xmltv") == 0) { if (i < argc - 1 && isanumber(argv[i + 1])) { @@ -2480,7 +2486,7 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) continue; } } - if (strcmp(argv[i], "-xmltvliveinterval") == 0) + if (strcmp(argv[i], "--xmltvliveinterval") == 0) { if (i < argc - 1 && isanumber(argv[i + 1])) { @@ -2494,7 +2500,7 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) continue; } } - if (strcmp(argv[i], "-xmltvoutputinterval") == 0) + if (strcmp(argv[i], "--xmltvoutputinterval") == 0) { if (i < argc - 1 && isanumber(argv[i + 1])) { @@ -2508,13 +2514,13 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) continue; } } - if (strcmp(argv[i], "-xmltvonlycurrent") == 0) + if (strcmp(argv[i], "--xmltvonlycurrent") == 0) { opt->xmltvonlycurrent = 1; i++; // why do we skip next? continue; } - if (strcmp(argv[i], "-unixts") == 0) + if (strcmp(argv[i], "--unixts") == 0) { if (i < argc - 1) { @@ -2533,31 +2539,31 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) } else { - fatal(EXIT_MALFORMED_PARAMETER, "-unixts has no argument.\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--unixts has no argument.\n"); } } - if (strcmp(argv[i], "-sects") == 0) + if (strcmp(argv[i], "--sects") == 0) { opt->date_format = ODF_SECONDS; continue; } - if (strcmp(argv[i], "-datets") == 0) + if (strcmp(argv[i], "--datets") == 0) { opt->date_format = ODF_DATE; continue; } - if (strcmp(argv[i], "-teletext") == 0) + if (strcmp(argv[i], "--teletext") == 0) { opt->demux_cfg.codec = CCX_CODEC_TELETEXT; continue; } - if (strcmp(argv[i], "-noteletext") == 0) + if (strcmp(argv[i], "--no-teletext") == 0) { opt->demux_cfg.nocodec = CCX_CODEC_TELETEXT; continue; } /* Custom transcript */ - if (strcmp(argv[i], "-customtxt") == 0) + if (strcmp(argv[i], "--customtxt") == 0) { if (i < argc - 1) { @@ -2582,7 +2588,7 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) } else { - fatal(EXIT_INCOMPATIBLE_PARAMETERS, "customtxt cannot be set after -UCLA is used!\n"); + fatal(EXIT_INCOMPATIBLE_PARAMETERS, "customtxt cannot be set after --UCLA is used!\n"); } } else @@ -2594,12 +2600,12 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) } else { - fatal(EXIT_MALFORMED_PARAMETER, "-customtxt has no argument.\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--customtxt has no argument.\n"); } } /* Network stuff */ - if (strcmp(argv[i], "-udp") == 0) + if (strcmp(argv[i], "--udp") == 0) { if (i < argc - 1) { @@ -2609,7 +2615,7 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) char *colon = strchr(argv[i], ':'); if (at && !colon) { - fatal(EXIT_MALFORMED_PARAMETER, "If -udp contains an '@', it must also contain a ':'\n"); + fatal(EXIT_MALFORMED_PARAMETER, "If --udp contains an '@', it must also contain a ':'\n"); } else if (at && colon) { @@ -2636,10 +2642,10 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) } else { - fatal(EXIT_MALFORMED_PARAMETER, "-udp has no argument.\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--udp has no argument.\n"); } } - if (strcmp(argv[i], "-sendto") == 0) + if (strcmp(argv[i], "--sendto") == 0) { if (i < argc - 1) { @@ -2688,10 +2694,10 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) } else { - fatal(EXIT_MALFORMED_PARAMETER, "-sendto has no argument.\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--sendto has no argument.\n"); } } - if (strcmp(argv[i], "-tcp") == 0) + if (strcmp(argv[i], "--tcp") == 0) { if (i < argc - 1) { @@ -2706,10 +2712,10 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) } else { - fatal(EXIT_MALFORMED_PARAMETER, "-tcp has no argument.\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--tcp has no argument.\n"); } } - if (strcmp(argv[i], "-tcppassword") == 0) + if (strcmp(argv[i], "--tcp-password") == 0) { if (i < argc - 1) { @@ -2719,10 +2725,10 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) } else { - fatal(EXIT_MALFORMED_PARAMETER, "-tcppassword has no argument.\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--tcp-password has no argument.\n"); } } - if (strcmp(argv[i], "-tcpdesc") == 0) + if (strcmp(argv[i], "--tcp-description") == 0) { if (i < argc - 1) { @@ -2732,11 +2738,11 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) } else { - fatal(EXIT_MALFORMED_PARAMETER, "-tcpdesc has no argument.\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--tcpdesc has no argument.\n"); } } - if (strcmp(argv[i], "-font") == 0) + if (strcmp(argv[i], "--font") == 0) { if (i < argc - 1) { @@ -2746,10 +2752,10 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) } else { - fatal(EXIT_MALFORMED_PARAMETER, "-font has no argument.\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--font has no argument.\n"); } } - if (strcmp(argv[i], "-italics") == 0 && i < argc - 1) + if (strcmp(argv[i], "--italics") == 0 && i < argc - 1) { opt->enc_cfg.render_font_italics = argv[i + 1]; i++; @@ -2757,7 +2763,7 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) } #ifdef WITH_LIBCURL - if (strcmp(argv[i], "-curlposturl") == 0) + if (strcmp(argv[i], "--curlposturl") == 0) { if (i < argc - 1) { @@ -2767,18 +2773,18 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) } else { - fatal(EXIT_MALFORMED_PARAMETER, "-curlposturl has no argument.\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--curlposturl has no argument.\n"); } } #endif // WITH_LIBCURL #ifdef ENABLE_SHARING - if (strcmp(argv[i], "-enable-sharing") == 0) + if (strcmp(argv[i], "--enable-sharing") == 0) { opt->sharing_enabled = 1; continue; } - if (strcmp(argv[i], "-sharing-url") == 0) + if (strcmp(argv[i], "--sharing-url") == 0) { if (i < argc - 1) { @@ -2788,10 +2794,10 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) } else { - fatal(EXIT_MALFORMED_PARAMETER, "-sharing-url has no argument.\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--sharing-url has no argument.\n"); } } - if (strcmp(argv[i], "-translate") == 0) + if (strcmp(argv[i], "--translate") == 0) { if (i < argc - 1) { @@ -2803,10 +2809,10 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) } else { - fatal(EXIT_MALFORMED_PARAMETER, "-translate has no argument.\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--translate has no argument.\n"); } } - if (strcmp(argv[i], "-translate-auth") == 0) + if (strcmp(argv[i], "--translate-auth") == 0) { if (i < argc - 1) { @@ -2816,7 +2822,7 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) } else { - fatal(EXIT_MALFORMED_PARAMETER, "-translate-auth has no argument.\n"); + fatal(EXIT_MALFORMED_PARAMETER, "--translate-auth has no argument.\n"); } } #endif // ENABLE_SHARING From c55072677875ee766c6cf388da70eff0a686ca62 Mon Sep 17 00:00:00 2001 From: Asher <74317567+asher-gh@users.noreply.github.com> Date: Mon, 15 Jan 2024 08:50:36 +0000 Subject: [PATCH 09/27] Typo in compilation docs (#1588) * Typo in compilation docs * [Fix] Deprecated leptonica name With version 1.84.0, the library is changed from `liblept` to `libleptonica`. http://www.leptonica.org/source/version-notes.html --- docs/COMPILATION.MD | 2 +- linux/build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/COMPILATION.MD b/docs/COMPILATION.MD index 7189f71f7..10aa08a0d 100644 --- a/docs/COMPILATION.MD +++ b/docs/COMPILATION.MD @@ -57,7 +57,7 @@ cd ccextractor/linux ./build -without-rust # compile with debug info -./build -debug # same as ./build_debug +./build -debug # same as ./builddebug # compile with hardsubx [Optional] You need to set these environment variables correctly according to your machine, diff --git a/linux/build b/linux/build index 2d5f5652f..385a8d61b 100755 --- a/linux/build +++ b/linux/build @@ -85,7 +85,7 @@ SRC_FREETYPE="../src/thirdparty/freetype/autofit/autofit.c ../src/thirdparty/freetype/type42/type42.c ../src/thirdparty/freetype/winfonts/winfnt.c" BLD_SOURCES="../src/ccextractor.c $SRC_CCX $SRC_GPAC $SRC_ZLIB $SRC_LIBPNG $SRC_HASH $SRC_PROTOBUF $SRC_UTF8PROC $SRC_FREETYPE" -BLD_LINKER="$BLD_LINKER -lm -zmuldefs -l tesseract -l lept -lpthread -ldl -lgpac" +BLD_LINKER="$BLD_LINKER -lm -zmuldefs -l tesseract -l leptonica -lpthread -ldl -lgpac" echo "Running pre-build script..." ./pre-build.sh From f449d06cd15688250edeae0afbb5c8da67b8f6ec Mon Sep 17 00:00:00 2001 From: Prateek Sunal Date: Mon, 5 Feb 2024 00:27:04 +0530 Subject: [PATCH 10/27] chore: lint fixes acc to rustfmt (#1598) --- src/rust/src/decoder/window.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rust/src/decoder/window.rs b/src/rust/src/decoder/window.rs index fbd4d024c..868709193 100644 --- a/src/rust/src/decoder/window.rs +++ b/src/rust/src/decoder/window.rs @@ -441,13 +441,13 @@ impl PenStyle { }; let color = PenColor { - /// White(2,2,2) i.e 10,10,10 i.e 42 + // White(2,2,2) i.e 10,10,10 i.e 42 fg_color: 42, fg_opacity: Opacity::Solid, - /// Either N/A or black, still always 0 + // Either N/A or black, still always 0 bg_color: 0, bg_opacity, - /// Either N/A or black, still always 0 + // Either N/A or black, still always 0 edge_color: 0, }; From deaa4a68e05ba6df69312b4f4e0b13b24326ab53 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 4 Feb 2024 19:59:52 +0100 Subject: [PATCH 11/27] Bump microsoft/setup-msbuild from 1.3.1 to 2.0.0 (#1593) Bumps [microsoft/setup-msbuild](https://github.com/microsoft/setup-msbuild) from 1.3.1 to 2.0.0. - [Release notes](https://github.com/microsoft/setup-msbuild/releases) - [Changelog](https://github.com/microsoft/setup-msbuild/blob/main/building-release.md) - [Commits](https://github.com/microsoft/setup-msbuild/compare/v1.3.1...v2.0.0) --- updated-dependencies: - dependency-name: microsoft/setup-msbuild dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build_windows.yml | 4 ++-- .github/workflows/release.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build_windows.yml b/.github/workflows/build_windows.yml index 3ecbf1c8b..ffee19656 100644 --- a/.github/workflows/build_windows.yml +++ b/.github/workflows/build_windows.yml @@ -27,7 +27,7 @@ jobs: - name: Check out repository uses: actions/checkout@v4 - name: Setup MSBuild.exe - uses: microsoft/setup-msbuild@v1.3.1 + uses: microsoft/setup-msbuild@v2.0.0 - name: Install llvm and clang run: choco install llvm gpac - uses: actions-rs/toolchain@v1 @@ -69,7 +69,7 @@ jobs: - name: Check out repository uses: actions/checkout@v4 - name: Setup MSBuild.exe - uses: microsoft/setup-msbuild@v1.3.1 + uses: microsoft/setup-msbuild@v2.0.0 - name: Install llvm and clang run: choco install llvm gpac - name: Setup Vcpkg diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 60ef7079a..7fe41c218 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,7 +16,7 @@ jobs: run: echo ::set-output name=VERSION::${GITHUB_REF/refs\/tags\/v/} shell: bash - name: Setup MSBuild.exe - uses: microsoft/setup-msbuild@v1.3.1 + uses: microsoft/setup-msbuild@v2.0.0 - name: Install llvm and clang uses: egor-tensin/setup-clang@v1 with: From 2d2a210c5453984be4aefb565b1b4871cc5cabae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 4 Feb 2024 20:02:21 +0100 Subject: [PATCH 12/27] Bump actions/cache from 3 to 4 (#1589) Bumps [actions/cache](https://github.com/actions/cache) from 3 to 4. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build_linux.yml | 2 +- .github/workflows/build_mac.yml | 2 +- .github/workflows/format.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml index 51a1e5bcb..cd3349ecb 100644 --- a/.github/workflows/build_linux.yml +++ b/.github/workflows/build_linux.yml @@ -96,7 +96,7 @@ jobs: run: sudo apt update && sudo apt-get install libgpac-dev - uses: actions/checkout@v4 - name: cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | src/rust/.cargo/registry diff --git a/.github/workflows/build_mac.yml b/.github/workflows/build_mac.yml index 135d1e622..c654aceac 100644 --- a/.github/workflows/build_mac.yml +++ b/.github/workflows/build_mac.yml @@ -95,7 +95,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | src/rust/.cargo/registry diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 98d580264..7a3d84f1d 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -32,7 +32,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | src/rust/.cargo/registry From 2ada36d50ef3ab6e71b2cb0fceba602b2f87cd11 Mon Sep 17 00:00:00 2001 From: Ishan Grover <123376573+IshanGrover2004@users.noreply.github.com> Date: Sun, 18 Feb 2024 07:28:01 +0530 Subject: [PATCH 13/27] [FEATURE] Add SCC support to CEA-708 decoder (#1595) * feat: Add timing functions for SCC format in C & Rust * feat: Add SCC support to Rust 708 decoder * feat: Add SCC support to C 708 decoder * docs: fix symbol in scc_time format * chore: clippy fixes * docs: Add new feature in Changelog * fix: update SCC timing functions according to need * feat: Add new member(old caption end time) for overlapping situations * fix: update SCC timing functions according to need * feat: Add support for overlapping captions situations * fix: frame formula for timings * feat: Add support for orientation of subtitles in C by adding necessary labels needed for it * feat: Add support for orientation of subtitles in Rust by adding necessary labels needed for it * docs: Add info for scc labels * chore: clippy fixes * docs: Add what `add_needed_scc_labels` do and correct parameters name --- docs/CHANGES.TXT | 1 + src/lib_ccx/ccx_common_timing.c | 28 +++++ src/lib_ccx/ccx_common_timing.h | 2 + src/lib_ccx/ccx_decoders_708.h | 1 + src/lib_ccx/ccx_decoders_708_output.c | 152 ++++++++++++++++++++++++++ src/lib_ccx/ccx_decoders_708_output.h | 15 ++- src/rust/src/decoder/output.rs | 2 + src/rust/src/decoder/timing.rs | 28 +++++ src/rust/src/decoder/tv_screen.rs | 147 ++++++++++++++++++++++++- 9 files changed, 369 insertions(+), 7 deletions(-) diff --git a/docs/CHANGES.TXT b/docs/CHANGES.TXT index 214584c72..0c65a7fe5 100644 --- a/docs/CHANGES.TXT +++ b/docs/CHANGES.TXT @@ -1,5 +1,6 @@ 0.95 (to be released) ----------------- +- New: Add SCC support for CEA-708 decoder (#1595) - Fix: respect `-stdout` even if multiple CC tracks are present in a Matroska input file (#1453) - Fix: crash in Rust decoder on ATSC1.0 TS Files (#1407) - Removed the --with-gui flag for linux/configure and mac/configure (use the Flutter GUI instead) diff --git a/src/lib_ccx/ccx_common_timing.c b/src/lib_ccx/ccx_common_timing.c index d1fca4282..1fd123cb9 100644 --- a/src/lib_ccx/ccx_common_timing.c +++ b/src/lib_ccx/ccx_common_timing.c @@ -295,6 +295,34 @@ LLONG get_fts_max(struct ccx_common_timing_ctx *ctx) return ctx->fts_max + ctx->fts_global; } +/** + * SCC Time formatting + */ +size_t print_scc_time(struct ccx_boundary_time time, char *buf) +{ + char *fmt = "%02u:%02u:%02u;%02u"; + double frame; + + frame = ((double)(time.time_in_ms - 1000 * (time.ss + 60 * (time.mm + 60 * time.hh))) * 29.97 / 1000); + + return (size_t)sprintf(buf + time.set, fmt, time.hh, time.mm, time.ss, (unsigned)frame); +} + +struct ccx_boundary_time get_time(LLONG time) +{ + if (time < 0) // Avoid loss of data warning with abs() + time = -time; + + struct ccx_boundary_time result; + result.hh = (unsigned)(time / 1000 / 60 / 60); + result.mm = (unsigned)(time / 1000 / 60 - 60 * result.hh); + result.ss = (unsigned)(time / 1000 - 60 * (result.mm + 60 * result.hh)); + result.time_in_ms = time; + result.set = (time < 0 ? 1 : 0); + + return result; +} + /** * Fill buffer with a time string using specified format * @param fmt has to contain 4 format specifiers for h, m, s and ms respectively diff --git a/src/lib_ccx/ccx_common_timing.h b/src/lib_ccx/ccx_common_timing.h index f54f4302c..1f157173c 100644 --- a/src/lib_ccx/ccx_common_timing.h +++ b/src/lib_ccx/ccx_common_timing.h @@ -77,6 +77,8 @@ struct ccx_common_timing_ctx *init_timing_ctx(struct ccx_common_timing_settings_ void set_current_pts(struct ccx_common_timing_ctx *ctx, LLONG pts); void add_current_pts(struct ccx_common_timing_ctx *ctx, LLONG pts); +struct ccx_boundary_time get_time(LLONG mstime); +size_t print_scc_time(struct ccx_boundary_time time, char *buf); int set_fts(struct ccx_common_timing_ctx *ctx); LLONG get_fts(struct ccx_common_timing_ctx *ctx, int current_field); LLONG get_fts_max(struct ccx_common_timing_ctx *ctx); diff --git a/src/lib_ccx/ccx_decoders_708.h b/src/lib_ccx/ccx_decoders_708.h index 8cbd01f8b..0fe0dde7d 100644 --- a/src/lib_ccx/ccx_decoders_708.h +++ b/src/lib_ccx/ccx_decoders_708.h @@ -302,6 +302,7 @@ typedef struct dtvcc_tv_screen LLONG time_ms_hide; unsigned int cc_count; int service_number; + int old_cc_time_end; } dtvcc_tv_screen; /** diff --git a/src/lib_ccx/ccx_decoders_708_output.c b/src/lib_ccx/ccx_decoders_708_output.c index c1bf3faa2..5697ad242 100644 --- a/src/lib_ccx/ccx_decoders_708_output.c +++ b/src/lib_ccx/ccx_decoders_708_output.c @@ -367,6 +367,155 @@ void dtvcc_write_sami(dtvcc_writer_ctx *writer, dtvcc_service_decoder *decoder, write_wrapped(encoder->dtvcc_writers[tv->service_number - 1].fd, buf, strlen(buf)); } +unsigned char adjust_odd_parity(const unsigned char value) +{ + unsigned int i, ones = 0; + for (i = 0; i < 8; i++) + { + if ((value & (1 << i)) != 0) + { + ones += 1; + } + } + if (ones % 2 == 0) + { + // make the number of ones always odd + return value | 0b10000000; + } + return value; +} + +void dtvcc_write_scc_header(dtvcc_tv_screen *tv, struct encoder_ctx *encoder) +{ + char *buf = (char *)encoder->buffer; + // 18 characters long + 2 new lines + memset(buf, 0, 20); + sprintf(buf, "Scenarist_SCC V1.0\n\n"); + + write_wrapped(encoder->dtvcc_writers[tv->service_number - 1].fd, buf, strlen(buf)); +} + +int count_captions_lines_scc(dtvcc_tv_screen *tv) +{ + int count = 0; + for (int i = 0; i < CCX_DTVCC_SCREENGRID_ROWS; i++) + { + if (!dtvcc_is_row_empty(tv, i)) + { + count++; + } + } + + return count; +} + +/** This function is designed to assign appropriate SSC labels for positioning subtitles based on their length. + * In some scenarios where the video stream provides lengthy subtitles that cannot fit within a single line. + * Single-line subtitle can be placed in 15th row(most bottom row) + * 2 line length subtitles can be placed in 14th and 15th row + * 3 line length subtitles can be placed in 13th, 14th and 15th row + */ +void add_needed_scc_labels(char *buf, int total_subtitle_count, int current_subtitle_count) +{ + switch (total_subtitle_count) + { + case 1: + // row 15, column 00 + sprintf(buf + strlen(buf), " 94e0 94e0"); + break; + case 2: + // 9440: row 14, column 00 | 94e0: row 15, column 00 + sprintf(buf + strlen(buf), current_subtitle_count == 1 ? " 9440 9440" : " 94e0 94e0"); + break; + default: + // 13e0: row 13, column 04 | 9440: row 14, column 00 | 94e0: row 15, column 00 + sprintf(buf + strlen(buf), current_subtitle_count == 1 ? " 13e0 13e0" : (current_subtitle_count == 2 ? " 9440 9440" : " 94e0 94e0")); + } +} + +void dtvcc_write_scc(dtvcc_writer_ctx *writer, dtvcc_service_decoder *decoder, struct encoder_ctx *encoder) +{ + dtvcc_tv_screen *tv = decoder->tv; + + if (dtvcc_is_screen_empty(tv, encoder)) + return; + + if (tv->time_ms_show + encoder->subs_delay < 0) + return; + + if (tv->cc_count == 2) + dtvcc_write_scc_header(tv, encoder); + + char *buf = (char *)encoder->buffer; + struct ccx_boundary_time time_show = get_time(tv->time_ms_show + encoder->subs_delay); + // when hiding subtract a frame (1 frame = 34 ms) + struct ccx_boundary_time time_end = get_time(tv->time_ms_hide + encoder->subs_delay - 34); + + if (tv->old_cc_time_end > time_show.time_in_ms) + { + // Correct the frame delay + time_show.time_in_ms -= 1000 / 29.97; + print_scc_time(time_show, buf); + sprintf(buf + strlen(buf), "\t942c 942c"); + time_show.time_in_ms += 1000 / 29.97; + // Clear the buffer and start pop on caption + sprintf(buf + strlen(buf), "94ae 94ae 9420 9420"); + } + else if (tv->old_cc_time_end < time_show.time_in_ms) + { + // Clear the screen for new caption + struct ccx_boundary_time time_to_display = get_time(tv->old_cc_time_end); + print_scc_time(time_to_display, buf); + sprintf(buf + strlen(buf), "\t942c 942c \n\n"); + // Correct the frame delay + time_show.time_in_ms -= 1000 / 29.97; + // Clear the buffer and start pop on caption in new time + print_scc_time(time_show, buf); + sprintf(buf + strlen(buf), "\t94ae 94ae 9420 9420"); + time_show.time_in_ms += 1000 / 29.97; + } + else + { + time_show.time_in_ms -= 1000 / 29.97; + print_scc_time(time_show, buf); + sprintf(buf + strlen(buf), "\t942c 942c 94ae 94ae 9420 9420"); + time_show.time_in_ms += 1000 / 29.97; + } + + int total_subtitle_count = count_captions_lines_scc(tv); + int current_subtitle_count = 0; + + for (int i = 0; i < CCX_DTVCC_SCREENGRID_ROWS; i++) + { + if (!dtvcc_is_row_empty(tv, i)) + { + current_subtitle_count++; + add_needed_scc_labels(buf, total_subtitle_count, current_subtitle_count); + + int first, last, bytes_written = 0; + dtvcc_get_write_interval(tv, i, &first, &last); + for (int j = first; j <= last; j++) + { + if (bytes_written % 2 == 0) + sprintf(buf + strlen(buf), " "); + sprintf(buf + strlen(buf), "%x", adjust_odd_parity(tv->chars[i][j].sym)); + bytes_written += 1; + } + // if byte pair are not even then make it even by adding 0x80 as padding + if (bytes_written % 2 == 1) + sprintf(buf + strlen(buf), "80 "); + else + sprintf(buf + strlen(buf), " "); + } + } + + // Display caption (942f 942f) + sprintf(buf + strlen(buf), "942f 942f \n\n"); + write_wrapped(encoder->dtvcc_writers[tv->service_number - 1].fd, buf, strlen(buf)); + + tv->old_cc_time_end = time_end.time_in_ms; +} + void dtvcc_write(dtvcc_writer_ctx *writer, dtvcc_service_decoder *decoder, struct encoder_ctx *encoder) { switch (encoder->write_format) @@ -382,6 +531,9 @@ void dtvcc_write(dtvcc_writer_ctx *writer, dtvcc_service_decoder *decoder, struc case CCX_OF_SAMI: dtvcc_write_sami(writer, decoder, encoder); break; + case CCX_OF_SCC: + dtvcc_write_scc(writer, decoder, encoder); + break; case CCX_OF_MCC: printf("REALLY BAD... [%s:%d]\n", __FILE__, __LINE__); break; diff --git a/src/lib_ccx/ccx_decoders_708_output.h b/src/lib_ccx/ccx_decoders_708_output.h index 3b9f6759f..63544df79 100644 --- a/src/lib_ccx/ccx_decoders_708_output.h +++ b/src/lib_ccx/ccx_decoders_708_output.h @@ -8,11 +8,11 @@ void dtvcc_write_done(dtvcc_tv_screen *tv, struct encoder_ctx *encoder); void dtvcc_writer_init(dtvcc_writer_ctx *writer, - char *base_filename, - int program_number, - int service_number, - enum ccx_output_format write_format, - struct encoder_cfg *cfg); + char *base_filename, + int program_number, + int service_number, + enum ccx_output_format write_format, + struct encoder_cfg *cfg); void dtvcc_writer_cleanup(dtvcc_writer_ctx *writer); void dtvcc_writer_output(dtvcc_writer_ctx *writer, dtvcc_service_decoder *decoder, struct encoder_ctx *encoder); @@ -30,6 +30,9 @@ void dtvcc_write_transcript(dtvcc_writer_ctx *writer, dtvcc_service_decoder *dec void dtvcc_write_sami_header(dtvcc_tv_screen *tv, struct encoder_ctx *encoder); void dtvcc_write_sami_footer(dtvcc_tv_screen *tv, struct encoder_ctx *encoder); void dtvcc_write_sami(dtvcc_writer_ctx *writer, dtvcc_service_decoder *decoder, struct encoder_ctx *encoder); +void dtvcc_write_scc_header(dtvcc_tv_screen *tv, struct encoder_ctx *encoder); +void add_needed_scc_labels(char *buf, int total_subtitle_count, int current_subtitle_count); +void dtvcc_write_scc(dtvcc_writer_ctx *writer, dtvcc_service_decoder *decoder, struct encoder_ctx *encoder); void dtvcc_write(dtvcc_writer_ctx *writer, dtvcc_service_decoder *decoder, struct encoder_ctx *encoder); -#endif /*_CCX_DECODERS_708_OUTPUT_H_*/ \ No newline at end of file +#endif /*_CCX_DECODERS_708_OUTPUT_H_*/ diff --git a/src/rust/src/decoder/output.rs b/src/rust/src/decoder/output.rs index fe13f6ff5..fd0c96dc3 100644 --- a/src/rust/src/decoder/output.rs +++ b/src/rust/src/decoder/output.rs @@ -20,6 +20,7 @@ pub struct Writer<'a> { pub no_font_color: bool, pub transcript_settings: &'a ccx_encoders_transcript_format, pub no_bom: i32, + pub old_cc_time_end: i32, } impl<'a> Writer<'a> { @@ -42,6 +43,7 @@ impl<'a> Writer<'a> { no_font_color: is_true(no_font_color), transcript_settings, no_bom, + old_cc_time_end: 0, } } /// Write subtitles to the file diff --git a/src/rust/src/decoder/timing.rs b/src/rust/src/decoder/timing.rs index e65aad9e2..5702359ef 100644 --- a/src/rust/src/decoder/timing.rs +++ b/src/rust/src/decoder/timing.rs @@ -47,3 +47,31 @@ pub fn get_time_str(time: LLONG) -> String { let ms = time - 1000 * (ss + 60 * (mm + 60 * hh)); format!("{:02}:{:02}:{:02},{:03}", hh, mm, ss, ms) } + +impl ccx_boundary_time { + /// Returns ccx_boundary_time from given time + pub fn get_time(time: LLONG) -> Self { + let hh = time / 1000 / 60 / 60; + let mm = time / 1000 / 60 - 60 * hh; + let ss = time / 1000 - 60 * (mm + 60 * hh); + + Self { + hh: hh as i32, + mm: mm as i32, + ss: ss as i32, + time_in_ms: time, + set: Default::default(), + } + } +} + +/// Returns a hh:mm:ss;frame string of time for SCC format +pub fn get_scc_time_str(time: ccx_boundary_time) -> String { + // Feel sorry for formatting:( + let frame: u8 = (((time.time_in_ms + - 1000 * ((time.ss as i64) + 60 * ((time.mm as i64) + 60 * (time.hh as i64)))) + as f64) + * 29.97 + / 1000.0) as u8; + format!("{:02}:{:02}:{:02};{:02}", time.hh, time.mm, time.ss, frame) +} diff --git a/src/rust/src/decoder/tv_screen.rs b/src/rust/src/decoder/tv_screen.rs index 71f3f2b2f..43128b9bf 100644 --- a/src/rust/src/decoder/tv_screen.rs +++ b/src/rust/src/decoder/tv_screen.rs @@ -3,6 +3,7 @@ //! TV screen contains the captions to be displayed. //! Captions are added to TV screen from a window when any of DSW, HDW, TGW, DLW or CR commands are received +use std::cmp::Ordering; #[cfg(unix)] use std::os::unix::prelude::IntoRawFd; #[cfg(windows)] @@ -10,7 +11,7 @@ use std::os::windows::io::IntoRawHandle; use std::{ffi::CStr, fs::File}; use super::output::{color_to_hex, write_char, Writer}; -use super::timing::get_time_str; +use super::timing::{get_scc_time_str, get_time_str}; use super::{CCX_DTVCC_SCREENGRID_COLUMNS, CCX_DTVCC_SCREENGRID_ROWS}; use crate::{ bindings::*, @@ -128,6 +129,7 @@ impl dtvcc_tv_screen { ccx_output_format::CCX_OF_SRT => self.write_srt(writer), ccx_output_format::CCX_OF_SAMI => self.write_sami(writer), ccx_output_format::CCX_OF_TRANSCRIPT => self.write_transcript(writer), + ccx_output_format::CCX_OF_SCC => self.write_scc(writer), _ => { self.write_debug(); Err("Unsupported write format".to_owned()) @@ -358,6 +360,149 @@ impl dtvcc_tv_screen { Ok(()) } + fn count_captions_lines_scc(&self) -> usize { + (0..CCX_DTVCC_SCREENGRID_ROWS) + .filter(|&row_index| !self.is_row_empty(row_index as usize)) + .count() + } + + /// Write captions in SCC format + pub fn write_scc(&self, writer: &mut Writer) -> Result<(), String> { + fn adjust_odd_parity(value: u8) -> u8 { + let mut ones = 0; + for i in 0..=7 { + if value & (1 << i) != 0 { + ones += 1; + } + } + if ones % 2 == 0 { + 0b10000000 | value + } else { + value + } + } + // This function is designed to assign appropriate SSC labels for positioning subtitles based on their length. + // In some scenarios where the video stream provides lengthy subtitles that cannot fit within a single line. + // Single-line subtitle can be placed in 15th row(most bottom row) + // 2 line length subtitles can be placed in 14th and 15th row + // 3 line length subtitles can be placed in 13th, 14th and 15th row + fn add_needed_scc_labels( + buf: &mut String, + total_subtitle_count: usize, + current_subtitle_count: usize, + ) { + match total_subtitle_count { + // row 15, column 00 + 1 => buf.push_str(" 94e0 94e0"), + 2 => { + if current_subtitle_count == 1 { + // row 14, column 00 + buf.push_str(" 9440 9440"); + } else { + // row 15, column 00 + buf.push_str(" 94e0 94e0") + } + } + _ => { + if current_subtitle_count == 1 { + // row 13, column 04 + buf.push_str(" 13e0 13e0"); + } else if current_subtitle_count == 2 { + // row 14, column 00 + buf.push_str(" 9440 9440"); + } else { + // row 15, column 00 + buf.push_str(" 94e0 94e0") + } + } + } + } + if self.is_screen_empty(writer) { + return Ok(()); + } + + if self.time_ms_show + writer.subs_delay < 0 { + return Ok(()); + } + + if self.cc_count == 2 { + writer.write_to_file(b"Scenarist_SCC V1.0\n\n")?; + } + + if writer.old_cc_time_end == 0 { + writer.old_cc_time_end = self.time_ms_show as i32; + } + + let mut buf = String::new(); + let mut time_show = ccx_boundary_time::get_time(self.time_ms_show); + let time_end = ccx_boundary_time::get_time(self.time_ms_hide); + + // Caption overlapping situation + match writer.old_cc_time_end.cmp(&(time_show.time_in_ms as i32)) { + Ordering::Greater => { + // Correct the frame delay + time_show.time_in_ms -= 1000 / 29.97 as i64; + buf.push_str(&(get_scc_time_str(time_show) + "\t942c 942c ").to_owned()); + time_show.time_in_ms += 1000 / 29.97 as i64; + // Clear the buffer and start pop on caption + buf.push_str("94ae 94ae 9420 9420"); + } + Ordering::Less => { + // Clear the screen for new caption + let time_to_display = ccx_boundary_time::get_time(writer.old_cc_time_end as i64); + buf.push_str(&(get_scc_time_str(time_to_display) + "\t942c 942c \n\n").to_owned()); + // Correct the frame delay + time_show.time_in_ms -= 1000 / 29.97 as i64; + // Clear the buffer and start pop on caption in new time + buf.push_str(&(get_scc_time_str(time_show) + "\t94ae 94ae 9420 9420").to_owned()); + time_show.time_in_ms += 1000 / 29.97 as i64; + } + Ordering::Equal => { + time_show.time_in_ms -= 1000 / 29.97 as i64; + buf.push_str( + &(get_scc_time_str(time_show) + "\t942c 942c 94ae 94ae 9420 9420").to_owned(), + ); + time_show.time_in_ms += 1000 / 29.97 as i64; + } + } + + let total_subtitle_count = self.count_captions_lines_scc(); + let mut current_subtitle_count = 0; + + for row_index in 0..CCX_DTVCC_SCREENGRID_ROWS as usize { + if !self.is_row_empty(row_index) { + current_subtitle_count += 1; + add_needed_scc_labels(&mut buf, total_subtitle_count, current_subtitle_count); + + let (first, last) = self.get_write_interval(row_index); + debug!("First: {}, Last: {}", first, last); + + let mut bytes_written = 0; + for i in 0..last + 1 { + if bytes_written % 2 == 0 { + buf.push(' '); + } + let adjusted_val = adjust_odd_parity(self.chars[row_index][i].sym as u8); + buf = format!("{}{:x}", buf, adjusted_val); + bytes_written += 1; + } + // add 0x80 padding and form byte pair if the last byte pair is not form + if bytes_written % 2 == 1 { + buf.push_str("80 "); + } else { + buf.push(' '); + } + } + } + + // Display caption (942f 942f) + buf.push_str("942f 942f \n\n"); + writer.write_to_file(buf.as_bytes())?; + + writer.old_cc_time_end = time_end.time_in_ms as i32; + Ok(()) + } + /// Write debug messages /// /// Write all characters,show and hide time as a debug log From 89a12a7dd034c508ff6382bb2922274f3e53e6ff Mon Sep 17 00:00:00 2001 From: Ishan Grover <123376573+IshanGrover2004@users.noreply.github.com> Date: Sun, 3 Mar 2024 22:28:20 +0530 Subject: [PATCH 14/27] Bump `rsmpeg` to latest version for `ffmpeg` bindings (#1600) * chore(deps): bump `rsmpeg` to latest version * docs: Mention in CHANGES.TXT --- docs/CHANGES.TXT | 1 + src/rust/Cargo.lock | 76 +++++++++++++++++++++++++++++++++++---------- src/rust/Cargo.toml | 9 +++--- 3 files changed, 65 insertions(+), 21 deletions(-) diff --git a/docs/CHANGES.TXT b/docs/CHANGES.TXT index 0c65a7fe5..a11a3e720 100644 --- a/docs/CHANGES.TXT +++ b/docs/CHANGES.TXT @@ -1,5 +1,6 @@ 0.95 (to be released) ----------------- +- Update: Bump rsmpeg to latest version for ffmpeg bindings (#1600) - New: Add SCC support for CEA-708 decoder (#1595) - Fix: respect `-stdout` even if multiple CC tracks are present in a Matroska input file (#1453) - Fix: crash in Rust decoder on ATSC1.0 TS Files (#1407) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index ce4977a95..cec3a6ea6 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -59,6 +59,29 @@ dependencies = [ "which", ] +[[package]] +name = "bindgen" +version = "0.69.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" +dependencies = [ + "bitflags 2.4.0", + "cexpr", + "clang-sys", + "itertools", + "lazy_static", + "lazycell", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.52", + "which", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -90,7 +113,7 @@ dependencies = [ name = "ccx_rust" version = "0.1.0" dependencies = [ - "bindgen", + "bindgen 0.64.0", "env_logger", "iconv", "leptonica-sys", @@ -221,6 +244,15 @@ dependencies = [ "libc", ] +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -239,7 +271,7 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eff3f1dc2f0112411228f8db99ca8a6a1157537a7887b28b1c91fdc4051fb326" dependencies = [ - "bindgen", + "bindgen 0.64.0", "pkg-config", "vcpkg", ] @@ -375,7 +407,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.52", ] [[package]] @@ -393,20 +425,30 @@ version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +[[package]] +name = "prettyplease" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" +dependencies = [ + "proc-macro2", + "syn 2.0.52", +] + [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -457,9 +499,9 @@ checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "rsmpeg" -version = "0.14.1+ffmpeg.6.0" +version = "0.14.2+ffmpeg.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "055510ebd8693dfe70570352b19a9147314da95e7435477526b976fc83b04455" +checksum = "927012cd6ae43519f519741f4a69602ce3a47cf84750784da124dffd03527cc0" dependencies = [ "libc", "paste", @@ -488,11 +530,11 @@ dependencies = [ [[package]] name = "rusty_ffmpeg" -version = "0.13.1+ffmpeg.6.0" +version = "0.13.3+ffmpeg.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7c726b08ea3ed199e21f6f4b3a1c23fc56a154be731b4445e4ef9ee004cffc" +checksum = "716adffa5f909c8533611b1dab9ab5666bece35687845865b75ed6a990fc239c" dependencies = [ - "bindgen", + "bindgen 0.69.4", "camino", "libc", "once_cell", @@ -517,7 +559,7 @@ checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.52", ] [[package]] @@ -545,9 +587,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.32" +version = "2.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2" +checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" dependencies = [ "proc-macro2", "quote", @@ -569,7 +611,7 @@ version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd33f6f216124cfaf0fa86c2c0cdf04da39b6257bd78c5e44fa4fa98c3a5857b" dependencies = [ - "bindgen", + "bindgen 0.64.0", "leptonica-sys", "pkg-config", "vcpkg", @@ -592,7 +634,7 @@ checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" dependencies = [ "proc-macro2", "quote", - "syn 2.0.32", + "syn 2.0.52", ] [[package]] diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 027d76460..f38de8814 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -15,13 +15,14 @@ log = "0.4.0" env_logger = "0.8.4" iconv = "0.1.1" palette = "0.6.0" -rsmpeg = { version = "0.14.1", optional = true, features = ["link_system_ffmpeg"] } -tesseract-sys = { version = "0.5.14", optional = true, default-features = false} -leptonica-sys = { version = "0.4.3", optional = true, default-features = false} +rsmpeg = { version = "0.14.2", optional = true, features = [ + "link_system_ffmpeg", +] } +tesseract-sys = { version = "0.5.14", optional = true, default-features = false } +leptonica-sys = { version = "0.4.3", optional = true, default-features = false } [build-dependencies] bindgen = "0.64.0" [features] hardsubx_ocr = ["rsmpeg", "tesseract-sys", "leptonica-sys"] - From f08febfd61018b6dd225ccb98c1d935b926be626 Mon Sep 17 00:00:00 2001 From: Ishan Grover <123376573+IshanGrover2004@users.noreply.github.com> Date: Mon, 4 Mar 2024 04:29:44 +0530 Subject: [PATCH 15/27] [FEATURE] Create linux AppImage for building CCExtractor (#1592) * feat!: Add script for building AppImage * chore(delete): Remove `build-static.sh` file * refactor: Add link for logo photo * chore: Replace dead link --- linux/build-static.sh | 107 ---------------------------------------- linux/build_appimage.sh | 63 +++++++++++++++++++++++ 2 files changed, 63 insertions(+), 107 deletions(-) delete mode 100755 linux/build-static.sh create mode 100755 linux/build_appimage.sh diff --git a/linux/build-static.sh b/linux/build-static.sh deleted file mode 100755 index c7920a0ad..000000000 --- a/linux/build-static.sh +++ /dev/null @@ -1,107 +0,0 @@ -#!/usr/bin/env -S sh -ex - -#################################################################### -# setup by tracey apr 2012 -# updated version dec 2016 -# see: http://www.ccextractor.org/doku.php -#################################################################### - - -# build it static! -# simplest way is with linux alpine -# hop onto box with docker on it and cd to dir of the file you are staring at -# You will get a static-compiled binary and english language library file in the end. -if [ ! -e /tmp/cc/ccextractor-README.txt ]; then - rm -rf /tmp/cc; - mkdir -p -m777 /tmp/cc; - mkdir -p -m777 ../lib/tessdata/; - cp ccextractor-README.txt /tmp/cc/; - sudo docker run -v /tmp/cc:/tmp/cc --rm -it alpine:latest /tmp/cc/ccextractor-README.txt; - # NOTE: _AFTER_ testing/validating, you can promote it from "ccextractor.next" to "ccextractor"... ;-) - cp /tmp/cc/*traineddata ../lib/tessdata/; - chmod go-w ../lib/tessdata/; - exit 0; -fi - -# NOW we are inside docker container... -cd /tmp/cc; - - -# we want tesseract (for OCR) -echo ' -http://dl-cdn.alpinelinux.org/alpine/v3.5/main -http://dl-cdn.alpinelinux.org/alpine/v3.5/community -' >| /etc/apk/repositories; -apk update; apk upgrade; - -apk add --update bash zsh alpine-sdk perl; - -# (needed by various static builds below) -# Even though we're going to (re)builid tesseract from source statically, get its dependencies setup by -# installing it now, too. -apk add autoconf automake libtool tesseract-ocr-dev; - - -# Now comes the not-so-fun parts... Many packages _only_ provide .so files in their distros -- not the .a -# needed files for building something with it statically. Step through them now... - - -# libgif -wget https://sourceforge.net/projects/giflib/files/giflib-5.1.4.tar.gz; -zcat giflib*tar.gz | tar xf -; -cd giflib*/; -./configure --disable-shared --enable-static; make; make install; -hash -r; -cd -; - - -# libwebp -git clone https://github.com/webmproject/libwebp; -cd libwebp; -./autogen.sh; -./configure --disable-shared --enable-static; make; make install; -cd -; - - -# leptonica -wget http://www.leptonica.org/source/leptonica-1.73.tar.gz; -zcat leptonica*tar.gz | tar xf -; -cd leptonica*/; -./configure --disable-shared --enable-static; make; make install; -hash -r; -cd -; - - -# tesseract -git clone https://github.com/tesseract-ocr/tesseract; -cd tesseract; -./autogen.sh; -./configure --disable-shared --enable-static; make; make install; -cd -; - - -# ccextractor -- build static -git clone https://github.com/CCExtractor/ccextractor; -cd ccextractor/linux/; -perl -i -pe 's/O3 /O3 -static /' Makefile; -set +e; # this _will_ FAIL at the end.. -make ENABLE_OCR=yes; -set -e; -# I confess hand-compiling (cherrypicking which .a to use when there are 2, etc.) is fragile... -# But it was the _only_ way I could get a fully static build after hours of thrashing... -gcc -Wno-write-strings -Wno-pointer-sign -D_FILE_OFFSET_BITS=64 -DVERSION_FILE_PRESENT -O3 -std=gnu99 -s -DENABLE_OCR -DPNG_NO_CONFIG_H -I/usr/local/include/tesseract -I/usr/local/include/leptonica objs/*.o -o ccextractor \ - --static -lm -lgpac \ - /usr/local/lib/libtesseract.a \ - /usr/local/lib/liblept.a \ - /usr/local/lib/libgif.a \ - /usr/local/lib/libwebp.a \ - /usr/lib/libjpeg.a \ - /usr/lib/libtiff.a \ - /usr/lib/libgomp.a \ - -lstdc++; - -cp ccextractor /tmp/cc/ccextractor.next; -cd -; - -# get english lang trained data -wget https://github.com/tesseract-ocr/tessdata/raw/master/eng.traineddata; diff --git a/linux/build_appimage.sh b/linux/build_appimage.sh new file mode 100755 index 000000000..d586c4eb0 --- /dev/null +++ b/linux/build_appimage.sh @@ -0,0 +1,63 @@ +#!/bin/bash + +set -x +set -e + +# store the path of where the script is +OLD_CWD=$(readlink -f .) + +# store repo root as variable +REPO_ROOT=$(dirname $OLD_CWD) + +# Make a temp directory for building stuff which will be cleaned automatically +BUILD_DIR="$OLD_CWD/temp" + +# Check if temp directory exist, and if so then remove contents from it +# if not then create temp directory +if [ -d "$BUILD_DIR" ]; then + rm -r "$BUILD_DIR/*" | true +else + mkdir -p "$BUILD_DIR" +fi + +# make sure to clean up build dir, even if errors occur +cleanup() { + if [ -d "$BUILD_DIR" ]; then + rm -rf "$BUILD_DIR" + fi +} + +# Automatically trigger Cleanup function +trap cleanup EXIT + +# switch to build dir +pushd "$BUILD_DIR" + +# configure build files with CMake +# we need to explicitly set the install prefix, as CMake's default is /usr/local for some reason... +cmake "$REPO_ROOT/src" + +# build project and install files into AppDir +make -j$(nproc) ENABLE_OCR=yes + +# download linuxdeploy tool +wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage + +# make them executable +chmod +x linuxdeploy*.AppImage + +# Create AppDir +mkdir -p "$BUILD_DIR/AppDir" + +# Link of CCExtractor image of any of these resolution(8x8, 16x16, 20x20, 22x22, 24x24, 28x28, 32x32, 36x36, 42x42, +# 48x48, 64x64, 72x72, 96x96, 128x128, 160x160, 192x192, 256x256, 384x384, 480x480, 512x512) in png extension +PNG_LINK="https://ccextractor.org/images/ccextractor.png" + +# Download the image and put it in AppDir +wget "$PNG_LINK" -P AppDir + +# now, build AppImage using linuxdeploy +./linuxdeploy-x86_64.AppImage --appdir=AppDir -e ccextractor --create-desktop-file --output appimage -i AppDir/ccextractor.png + +# Move resulted AppImage binary to base directory +mv ccextractor*.AppImage "$OLD_CWD" From 312d10c001531102575729e73dd6217c09ad2e6a Mon Sep 17 00:00:00 2001 From: superbonaci Date: Sun, 24 Mar 2024 18:34:20 +0100 Subject: [PATCH 16/27] Update COMPILATION.MD: Add gpac-devel dependency for RHEL/Fedora (#1602) --- docs/COMPILATION.MD | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/COMPILATION.MD b/docs/COMPILATION.MD index 10aa08a0d..8bd7783cc 100644 --- a/docs/COMPILATION.MD +++ b/docs/COMPILATION.MD @@ -20,10 +20,10 @@ Debian: sudo apt-get install -y libgpac-dev libglew-dev libglfw3-dev cmake gcc libcurl4-gnutls-dev tesseract-ocr libtesseract-dev libleptonica-dev clang libclang-dev ``` -RHEL: +RHEL/Fedora: ```bash -yum install -y glew-devel glfw-devel cmake gcc libcurl-devel tesseract-devel leptonica-devel clang +yum install -y glew-devel glfw-devel cmake gcc libcurl-devel tesseract-devel leptonica-devel clang gpac-devel ``` Arch: From 3f504412f54dc88cdcfbdbf56e4657d51a6d9b49 Mon Sep 17 00:00:00 2001 From: Sberm <1007273067@qq.com> Date: Fri, 5 Apr 2024 12:07:39 +0800 Subject: [PATCH 17/27] Add gpac package in compilation guide on Archlinux (#1605) --- docs/COMPILATION.MD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/COMPILATION.MD b/docs/COMPILATION.MD index 8bd7783cc..a919164ac 100644 --- a/docs/COMPILATION.MD +++ b/docs/COMPILATION.MD @@ -28,7 +28,7 @@ yum install -y glew-devel glfw-devel cmake gcc libcurl-devel tesseract-devel lep Arch: ```bash -sudo paru -S glew glfw curl tesseract leptonica cmake gcc clang +sudo paru -S glew glfw curl tesseract leptonica cmake gcc clang gpac ``` Rust 1.54 or above is also required. [Install Rust](https://www.rust-lang.org/tools/install). Check specific compilation methods below, on how to compile without rust. From 5748042f6df5cd06ab1d5e09e7301494e7529de6 Mon Sep 17 00:00:00 2001 From: Ishan Grover <123376573+IshanGrover2004@users.noreply.github.com> Date: Fri, 24 May 2024 23:50:48 +0530 Subject: [PATCH 18/27] [FIX] Unexpected behavior of get_write_interval (#1609) * fix: Unexpected behavior of get_write_interval Adresses Issue#1606 * docs: Add changes to `CHANGES.TXT` --- docs/CHANGES.TXT | 1 + src/rust/src/decoder/tv_screen.rs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/CHANGES.TXT b/docs/CHANGES.TXT index a11a3e720..698035ed7 100644 --- a/docs/CHANGES.TXT +++ b/docs/CHANGES.TXT @@ -1,5 +1,6 @@ 0.95 (to be released) ----------------- +- Fix: Unexpected behavior of get_write_interval (#1609) - Update: Bump rsmpeg to latest version for ffmpeg bindings (#1600) - New: Add SCC support for CEA-708 decoder (#1595) - Fix: respect `-stdout` even if multiple CC tracks are present in a Matroska input file (#1453) diff --git a/src/rust/src/decoder/tv_screen.rs b/src/rust/src/decoder/tv_screen.rs index 43128b9bf..055f29739 100644 --- a/src/rust/src/decoder/tv_screen.rs +++ b/src/rust/src/decoder/tv_screen.rs @@ -105,7 +105,8 @@ impl dtvcc_tv_screen { /// Returns the bounds in which captions are present pub fn get_write_interval(&self, row_index: usize) -> (usize, usize) { let mut first = 0; - let mut last = CCX_DTVCC_SCREENGRID_COLUMNS as usize - 1; + let mut last = 0; + for col in 0..CCX_DTVCC_SCREENGRID_COLUMNS as usize { if self.chars[row_index][col].is_set() { first = col; From 8e3b145477a34983f31f6515dd2664e4c19e8acb Mon Sep 17 00:00:00 2001 From: Prateek Sunal Date: Wed, 29 May 2024 00:43:05 +0530 Subject: [PATCH 19/27] [FIX (Windows)] CI build (#1612) --- .github/workflows/build_windows.yml | 73 ++-- windows/.gitignore | 2 + windows/ccextractor.vcxproj | 47 ++- windows/ccextractor.vcxproj.filters | 617 ++++++---------------------- windows/vcpkg.json | 10 + 5 files changed, 213 insertions(+), 536 deletions(-) create mode 100644 windows/.gitignore create mode 100644 windows/vcpkg.json diff --git a/.github/workflows/build_windows.yml b/.github/workflows/build_windows.yml index ffee19656..1297de86c 100644 --- a/.github/workflows/build_windows.yml +++ b/.github/workflows/build_windows.yml @@ -3,6 +3,8 @@ name: Build CCExtractor on Windows env: RUSTFLAGS: -Ctarget-feature=+crt-static VCPKG_DEFAULT_TRIPLET: x64-windows-static + VCPKG_DEFAULT_BINARY_CACHE: C:\vcpkg\.cache + VCPKG_COMMIT: fba75d09065fcc76a25dcf386b1d00d33f5175af on: workflow_dispatch: @@ -22,36 +24,45 @@ on: jobs: build_release: - runs-on: windows-2019 + runs-on: windows-2022 steps: - name: Check out repository uses: actions/checkout@v4 - name: Setup MSBuild.exe - uses: microsoft/setup-msbuild@v2.0.0 - - name: Install llvm and clang - run: choco install llvm gpac + uses: microsoft/setup-msbuild@v1.3.1 + with: + msbuild-architecture: x64 + - name: Install gpac + run: choco install gpac --version 2.4.0 + - name: Setup vcpkg + run: mkdir C:\vcpkg\.cache + - name: Cache vcpkg + id: cache + uses: actions/cache@v3 + with: + path: | + C:\vcpkg\.cache + key: vcpkg-${{ runner.os }}-${{ env.VCPKG_COMMIT }} + - name: Build vcpkg + run: | + git clone https://github.com/microsoft/vcpkg + ./vcpkg/bootstrap-vcpkg.bat + - name: Install dependencies + run: ${{ github.workspace }}/vcpkg/vcpkg.exe install --x-install-root ${{ github.workspace }}/vcpkg/installed/ + working-directory: windows - uses: actions-rs/toolchain@v1 with: toolchain: stable override: true - name: Install Win 10 SDK uses: ilammy/msvc-dev-cmd@v1 - - name: Setup Vcpkg - id: vcpkg - uses: friendlyanon/setup-vcpkg@v1 - with: - committish: "2023.08.09" - cache-version: "3" - ignore-reserve-cache-error: true - - name: Install dependencies - run: cd vcpkg && vcpkg integrate install && vcpkg install leptonica tesseract ffmpeg --triplet x64-windows-static - name: build Release-Full env: LIBCLANG_PATH: "C:\\Program Files\\LLVM\\lib" LLVM_CONFIG_PATH: "C:\\Program Files\\LLVM\\bin\\llvm-config" CARGO_TARGET_DIR: "..\\..\\windows" BINDGEN_EXTRA_CLANG_ARGS: -fmsc-version=0 - VCPKG_ROOT: ${{ github.workspace }}\vcpkg + VCPKG_ROOT: ${{ github.workspace }}/vcpkg run: msbuild ccextractor.sln /p:Configuration=Release-Full /p:Platform=x64 working-directory: ./windows - name: Display version information @@ -64,23 +75,32 @@ jobs: ./windows/x64/Release-Full/ccextractorwinfull.exe ./windows/x64/Release-Full/*.dll build_debug: - runs-on: windows-2019 + runs-on: windows-2022 steps: - name: Check out repository uses: actions/checkout@v4 - name: Setup MSBuild.exe - uses: microsoft/setup-msbuild@v2.0.0 - - name: Install llvm and clang - run: choco install llvm gpac - - name: Setup Vcpkg - id: vcpkg - uses: friendlyanon/setup-vcpkg@v1 + uses: microsoft/setup-msbuild@v1.3.1 with: - committish: "2023.08.09" - cache-version: "3" - ignore-reserve-cache-error: true + msbuild-architecture: x64 + - name: Install gpac + run: choco install gpac --version 2.4.0 + - name: Setup vcpkg + run: mkdir C:\vcpkg\.cache + - name: Cache vcpkg + id: cache + uses: actions/cache@v3 + with: + path: | + C:\vcpkg\.cache + key: vcpkg-${{ runner.os }}-${{ env.VCPKG_COMMIT }} + - name: Build vcpkg + run: | + git clone https://github.com/microsoft/vcpkg + ./vcpkg/bootstrap-vcpkg.bat - name: Install dependencies - run: cd vcpkg && vcpkg integrate install && vcpkg install leptonica tesseract ffmpeg --triplet x64-windows-static + run: ${{ github.workspace }}/vcpkg/vcpkg.exe install --x-install-root ${{ github.workspace }}/vcpkg/installed/ + working-directory: windows - uses: actions-rs/toolchain@v1 with: toolchain: stable @@ -93,10 +113,11 @@ jobs: LLVM_CONFIG_PATH: "C:\\Program Files\\LLVM\\bin\\llvm-config" CARGO_TARGET_DIR: "..\\..\\windows" BINDGEN_EXTRA_CLANG_ARGS: -fmsc-version=0 - VCPKG_ROOT: ${{ github.workspace }}\vcpkg + VCPKG_ROOT: ${{ github.workspace }}/vcpkg run: msbuild ccextractor.sln /p:Configuration=Debug-Full /p:Platform=x64 working-directory: ./windows - name: Display version information + continue-on-error: true run: ./ccextractorwinfull.exe --version working-directory: ./windows/x64/Debug-Full - uses: actions/upload-artifact@v4 diff --git a/windows/.gitignore b/windows/.gitignore new file mode 100644 index 000000000..6b7a5ab6f --- /dev/null +++ b/windows/.gitignore @@ -0,0 +1,2 @@ +ccextractor +vcpkg_installed \ No newline at end of file diff --git a/windows/ccextractor.vcxproj b/windows/ccextractor.vcxproj index d2190f3c2..74f29588f 100644 --- a/windows/ccextractor.vcxproj +++ b/windows/ccextractor.vcxproj @@ -62,10 +62,8 @@ - - + + @@ -188,21 +186,26 @@ - + {0F0063C4-BCBC-4379-A6D5-84A5669C940A} ccextractor Win32Proj - 10.0.19041.0 + 10.0.22621.0 + + + true + x64-windows-static + true Application - v142 + v143 Application - v142 + v143 @@ -278,14 +281,14 @@ xcopy /y "$(ProjectDir)\dll\vcruntime140_1.dll" "$(OutDir)" xcopy /y "C:\Program Files\GPAC\libgpac.dll" "$(OutDir)" xcopy /y "C:\Program Files\GPAC\OpenSVCDecoder.dll" "$(OutDir)" - xcopy /y "C:\Program Files\GPAC\postproc-56.dll" "$(OutDir)" + xcopy /y "C:\Program Files\GPAC\postproc-57.dll" "$(OutDir)" xcopy /y "C:\Program Files\GPAC\swresample-4.dll" "$(OutDir)" - xcopy /y "C:\Program Files\GPAC\avfilter-8.dll" "$(OutDir)" - xcopy /y "C:\Program Files\GPAC\swscale-6.dll" "$(OutDir)" - xcopy /y "C:\Program Files\GPAC\avdevice-59.dll" "$(OutDir)" - xcopy /y "C:\Program Files\GPAC\avcodec-59.dll" "$(OutDir)" - xcopy /y "C:\Program Files\GPAC\avformat-59.dll" "$(OutDir)" - xcopy /y "C:\Program Files\GPAC\avutil-57.dll" "$(OutDir)" + xcopy /y "C:\Program Files\GPAC\avfilter-9.dll" "$(OutDir)" + xcopy /y "C:\Program Files\GPAC\swscale-7.dll" "$(OutDir)" + xcopy /y "C:\Program Files\GPAC\avdevice-60.dll" "$(OutDir)" + xcopy /y "C:\Program Files\GPAC\avcodec-60.dll" "$(OutDir)" + xcopy /y "C:\Program Files\GPAC\avformat-60.dll" "$(OutDir)" + xcopy /y "C:\Program Files\GPAC\avutil-58.dll" "$(OutDir)" xcopy /y "C:\Program Files\GPAC\libsslMD.dll" "$(OutDir)" xcopy /y "C:\Program Files\GPAC\libcryptoMD.dll" "$(OutDir)" @@ -325,14 +328,14 @@ xcopy /y "$(ProjectDir)\dll\vcruntime140_1.dll" "$(OutDir)" xcopy /y "C:\Program Files\GPAC\libgpac.dll" "$(OutDir)" xcopy /y "C:\Program Files\GPAC\OpenSVCDecoder.dll" "$(OutDir)" - xcopy /y "C:\Program Files\GPAC\postproc-56.dll" "$(OutDir)" + xcopy /y "C:\Program Files\GPAC\postproc-57.dll" "$(OutDir)" xcopy /y "C:\Program Files\GPAC\swresample-4.dll" "$(OutDir)" - xcopy /y "C:\Program Files\GPAC\avfilter-8.dll" "$(OutDir)" - xcopy /y "C:\Program Files\GPAC\swscale-6.dll" "$(OutDir)" - xcopy /y "C:\Program Files\GPAC\avdevice-59.dll" "$(OutDir)" - xcopy /y "C:\Program Files\GPAC\avcodec-59.dll" "$(OutDir)" - xcopy /y "C:\Program Files\GPAC\avformat-59.dll" "$(OutDir)" - xcopy /y "C:\Program Files\GPAC\avutil-57.dll" "$(OutDir)" + xcopy /y "C:\Program Files\GPAC\avfilter-9.dll" "$(OutDir)" + xcopy /y "C:\Program Files\GPAC\swscale-7.dll" "$(OutDir)" + xcopy /y "C:\Program Files\GPAC\avdevice-60.dll" "$(OutDir)" + xcopy /y "C:\Program Files\GPAC\avcodec-60.dll" "$(OutDir)" + xcopy /y "C:\Program Files\GPAC\avformat-60.dll" "$(OutDir)" + xcopy /y "C:\Program Files\GPAC\avutil-58.dll" "$(OutDir)" xcopy /y "C:\Program Files\GPAC\libsslMD.dll" "$(OutDir)" xcopy /y "C:\Program Files\GPAC\libcryptoMD.dll" "$(OutDir)" diff --git a/windows/ccextractor.vcxproj.filters b/windows/ccextractor.vcxproj.filters index 27083f551..8a7029ba0 100644 --- a/windows/ccextractor.vcxproj.filters +++ b/windows/ccextractor.vcxproj.filters @@ -183,108 +183,6 @@ Header Files\lib_ccx\ccx_encoders - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - Header Files @@ -300,39 +198,6 @@ Header Files - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - Header Files @@ -381,603 +246,379 @@ Header Files + + Header Files + + + Header Files + + + Header Files + + + Header Files + - - Source Files - - - Source Files\ccx_decoders - - - Source Files\ccx_decoders - - - Source Files\ccx_decoders - - - Source Files\ccx_decoders - - - Source Files\ccx_decoders - - - Source Files\ccx_decoders - - - Source Files\ccx_common - - - Source Files\ccx_common - - - Source Files\ccx_common - - - Source Files\ccx_common - - - Source Files\ccx_encoders - - - Source Files\ccx_encoders - - - Source Files\ccx_common - Source Files\ccx_decoders - - Source Files - - - Source Files - - - Source Files\ccx_decoders - - - Source Files\ccx_encoders - - - Source Files\ccx_encoders - - - Source Files\ccx_encoders - - - Source Files\ccx_encoders - - - Source Files\ccx_encoders - - - Source Files\ccx_encoders - - - Source Files\ccx_decoders - - - Source Files\ccx_decoders - - - Source Files\ccx_decoders - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files\ccx_encoders - - - Source Files\ccx_encoders - - - Source Files\ccx_encoders - - - Source Files\ccx_encoders - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files\lib_ccx - - - Source Files - - - Source Files\ccx_encoders - - - Source Files\ccx_encoders - Source Files\ccx_decoders Source Files\ccx_decoders - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - + Source Files - - Source Files\zlib - - - Source Files - - + Source Files - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - + Source Files - - Header Files\lib_ccx - + \ No newline at end of file diff --git a/windows/vcpkg.json b/windows/vcpkg.json new file mode 100644 index 000000000..caef96365 --- /dev/null +++ b/windows/vcpkg.json @@ -0,0 +1,10 @@ +{ + "name": "ccextractor", + "version": "1.0.0", + "dependencies": [ + "leptonica", + "tesseract", + "ffmpeg" + ], + "builtin-baseline": "fba75d09065fcc76a25dcf386b1d00d33f5175af" +} \ No newline at end of file From d6ccf1bfcba606c633b40349dcab07dfc77f73a5 Mon Sep 17 00:00:00 2001 From: Ishan Grover <123376573+IshanGrover2004@users.noreply.github.com> Date: Wed, 29 May 2024 12:58:24 +0530 Subject: [PATCH 20/27] [FEATURE] Port 708 decoder encoding module to RUST (#1607) * feat: Add `decoder/encoding` new module This `decoder/encoding.rs` file will contain the content of `lib_ccx/ccx_708_decoder_encoding.c` file * feat: Add encoding functions * feat: Add conditional compilation to include Rust functions * fix: conditional compilation logic * refactor: Use of match statement instead of if-else * fix: Calling C function for rust * feat: Enable `derive_default` feature --- src/lib_ccx/ccx_decoders_708_encoding.c | 4 +++ src/lib_ccx/ccx_decoders_708_encoding.h | 9 ++++- src/rust/build.rs | 2 ++ src/rust/src/decoder/encoding.rs | 45 +++++++++++++++++++++++++ src/rust/src/decoder/mod.rs | 1 + 5 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 src/rust/src/decoder/encoding.rs diff --git a/src/lib_ccx/ccx_decoders_708_encoding.c b/src/lib_ccx/ccx_decoders_708_encoding.c index 5cf9c74f6..b3d9508d4 100644 --- a/src/lib_ccx/ccx_decoders_708_encoding.c +++ b/src/lib_ccx/ccx_decoders_708_encoding.c @@ -12,6 +12,8 @@ EIA-708, SO INTERNALLY WE USE THIS TABLE (FOR CONVENIENCE) A0-FF -> Group G1 as is - non-English characters and symbols */ +#if defined(DISABLE_RUST) + unsigned char dtvcc_get_internal_from_G0(unsigned char g0_char) { return g0_char; @@ -43,3 +45,5 @@ unsigned char dtvcc_get_internal_from_G3(unsigned char g3_char) // Rest unmapped, so we return a blank space return 0x20; } + +#endif diff --git a/src/lib_ccx/ccx_decoders_708_encoding.h b/src/lib_ccx/ccx_decoders_708_encoding.h index 0318a0f1c..ef7ca2a84 100644 --- a/src/lib_ccx/ccx_decoders_708_encoding.h +++ b/src/lib_ccx/ccx_decoders_708_encoding.h @@ -1,11 +1,18 @@ #ifndef _CCX_DECODERS_708_ENCODING_H_ #define _CCX_DECODERS_708_ENCODING_H_ -#define CCX_DTVCC_MUSICAL_NOTE_CHAR 9836 // Unicode Character 'BEAMED SIXTEENTH NOTES' +#define CCX_DTVCC_MUSICAL_NOTE_CHAR 9836 // Unicode Character 'BEAMED SIXTEENTH NOTES' +#ifndef DISABLE_RUST +extern unsigned char dtvcc_get_internal_from_G0(unsigned char g0_char); +extern unsigned char dtvcc_get_internal_from_G1(unsigned char g1_char); +extern unsigned char dtvcc_get_internal_from_G2(unsigned char g2_char); +extern unsigned char dtvcc_get_internal_from_G3(unsigned char g3_char); +#else unsigned char dtvcc_get_internal_from_G0(unsigned char g0_char); unsigned char dtvcc_get_internal_from_G1(unsigned char g1_char); unsigned char dtvcc_get_internal_from_G2(unsigned char g2_char); unsigned char dtvcc_get_internal_from_G3(unsigned char g3_char); +#endif #endif /*_CCX_DECODERS_708_ENCODING_H_*/ diff --git a/src/rust/build.rs b/src/rust/build.rs index f8ecc04c8..03e6157f6 100644 --- a/src/rust/build.rs +++ b/src/rust/build.rs @@ -59,6 +59,8 @@ fn main() { } let bindings = builder + .derive_default(true) + .no_default("dtvcc_pen_attribs|dtvcc_pen_color|dtvcc_symbol") // Finish the builder and generate the bindings. .generate() // Unwrap the Result and panic on failure. diff --git a/src/rust/src/decoder/encoding.rs b/src/rust/src/decoder/encoding.rs new file mode 100644 index 000000000..2671cedd9 --- /dev/null +++ b/src/rust/src/decoder/encoding.rs @@ -0,0 +1,45 @@ +/// 256 BYTES IS ENOUGH FOR ALL THE SUPPORTED CHARACTERS IN +/// EIA-708, SO INTERNALLY WE USE THIS TABLE (FOR CONVENIENCE) +/// +/// 00-1F -> Characters that are in the G2 group in 20-3F, +/// except for 06, which is used for the closed captions +/// sign "CC" which is defined in group G3 as 00. (this +/// is by the article 33). +/// 20-7F -> Group G0 as is - corresponds to the ASCII code +/// 80-9F -> Characters that are in the G2 group in 60-7F +/// (there are several blank characters here, that's OK) +/// A0-FF -> Group G1 as is - non-English characters and symbols + +// NOTE: Same as `lib_ccx/ccx_decoder_708_encoding.c` file + +#[no_mangle] +pub extern "C" fn dtvcc_get_internal_from_G0(g0_char: u8) -> u8 { + g0_char +} + +#[no_mangle] +pub extern "C" fn dtvcc_get_internal_from_G1(g1_char: u8) -> u8 { + g1_char +} + +/// G2: Extended Control Code Set 1 +#[no_mangle] +pub extern "C" fn dtvcc_get_internal_from_G2(g2_char: u8) -> u8 { + match g2_char { + 0x20..=0x3F => g2_char - 0x20, + 0x60..=0x7F => g2_char + 0x20, + _ => 0x20, + } +} + +/// G3: Future Characters and Icon Expansion +#[no_mangle] +pub extern "C" fn dtvcc_get_internal_from_G3(g3_char: u8) -> u8 { + if g3_char == 0xa0 { + // The "CC" (closed captions) sign + 0x06 + } else { + // Rest unmapped, so we return a blank space + 0x20 + } +} diff --git a/src/rust/src/decoder/mod.rs b/src/rust/src/decoder/mod.rs index e13c7ed2d..2ee5c26bc 100644 --- a/src/rust/src/decoder/mod.rs +++ b/src/rust/src/decoder/mod.rs @@ -3,6 +3,7 @@ //! Provides a CEA 708 decoder as defined by ANSI/CTA-708-E R-2018 mod commands; +mod encoding; mod output; mod service_decoder; mod timing; From f12f12b9165c83d59e6ec43876ae8701dd354cf6 Mon Sep 17 00:00:00 2001 From: Ishan Grover <123376573+IshanGrover2004@users.noreply.github.com> Date: Wed, 3 Jul 2024 23:01:39 +0530 Subject: [PATCH 21/27] [FEAT] Create `lib_ccxr` and `libccxr_exports` (#1621) * create lib_ccxr and libccxr_exports * chore: Fix bindgen crate version * chore: Fix rsmpeg crate version * docs: Add PR info in Changelogs --------- Co-authored-by: Elbert Ronnie --- .gitignore | 3 ++- docs/CHANGES.TXT | 1 + src/rust/Cargo.lock | 5 +++++ src/rust/Cargo.toml | 1 + src/rust/lib_ccxr/Cargo.lock | 7 +++++++ src/rust/lib_ccxr/Cargo.toml | 17 +++++++++++++++++ src/rust/lib_ccxr/src/lib.rs | 1 + src/rust/lib_ccxr/src/util/mod.rs | 1 + src/rust/src/lib.rs | 1 + src/rust/src/libccxr_exports/mod.rs | 1 + 10 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 src/rust/lib_ccxr/Cargo.lock create mode 100644 src/rust/lib_ccxr/Cargo.toml create mode 100644 src/rust/lib_ccxr/src/lib.rs create mode 100644 src/rust/lib_ccxr/src/util/mod.rs create mode 100644 src/rust/src/libccxr_exports/mod.rs diff --git a/.gitignore b/.gitignore index a1ef235b5..3f8a2ed82 100644 --- a/.gitignore +++ b/.gitignore @@ -149,7 +149,8 @@ src/rust/CMakeCache.txt src/rust/Makefile src/rust/cmake_install.cmake src/rust/target/ +src/rust/lib_ccxr/target/ windows/ccx_rust.lib windows/*/debug/* windows/*/CACHEDIR.TAG -windows/.rustc_info.json \ No newline at end of file +windows/.rustc_info.json diff --git a/docs/CHANGES.TXT b/docs/CHANGES.TXT index 698035ed7..39c2104ae 100644 --- a/docs/CHANGES.TXT +++ b/docs/CHANGES.TXT @@ -1,5 +1,6 @@ 0.95 (to be released) ----------------- +- New: Create `lib_ccxr` and `libccxr_exports` (#1621) - Fix: Unexpected behavior of get_write_interval (#1609) - Update: Bump rsmpeg to latest version for ffmpeg bindings (#1600) - New: Add SCC support for CEA-708 decoder (#1595) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index cec3a6ea6..9b59367c1 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -117,6 +117,7 @@ dependencies = [ "env_logger", "iconv", "leptonica-sys", + "lib_ccxr", "log", "palette", "rsmpeg", @@ -276,6 +277,10 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "lib_ccxr" +version = "0.1.0" + [[package]] name = "libc" version = "0.2.147" diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index f38de8814..93ca96dd4 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -20,6 +20,7 @@ rsmpeg = { version = "0.14.2", optional = true, features = [ ] } tesseract-sys = { version = "0.5.14", optional = true, default-features = false } leptonica-sys = { version = "0.4.3", optional = true, default-features = false } +lib_ccxr = { path = "lib_ccxr" } [build-dependencies] bindgen = "0.64.0" diff --git a/src/rust/lib_ccxr/Cargo.lock b/src/rust/lib_ccxr/Cargo.lock new file mode 100644 index 000000000..7532d4515 --- /dev/null +++ b/src/rust/lib_ccxr/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "lib_ccxr" +version = "0.1.0" diff --git a/src/rust/lib_ccxr/Cargo.toml b/src/rust/lib_ccxr/Cargo.toml new file mode 100644 index 000000000..ca3612505 --- /dev/null +++ b/src/rust/lib_ccxr/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "lib_ccxr" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] + +[features] +default = ["enable_sharing", "wtv_debug", "enable_ffmpeg", "debug", "with_libcurl"] +enable_sharing = [] +wtv_debug = [] +enable_ffmpeg = [] +debug_out = [] +debug = [] +with_libcurl = [] diff --git a/src/rust/lib_ccxr/src/lib.rs b/src/rust/lib_ccxr/src/lib.rs new file mode 100644 index 000000000..812d1edf2 --- /dev/null +++ b/src/rust/lib_ccxr/src/lib.rs @@ -0,0 +1 @@ +pub mod util; diff --git a/src/rust/lib_ccxr/src/util/mod.rs b/src/rust/lib_ccxr/src/util/mod.rs new file mode 100644 index 000000000..daf5935ac --- /dev/null +++ b/src/rust/lib_ccxr/src/util/mod.rs @@ -0,0 +1 @@ +//! Provides basic utilities used throughout the program. diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index a76faa419..1fec8fa5e 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -15,6 +15,7 @@ pub mod bindings { pub mod decoder; #[cfg(feature = "hardsubx_ocr")] pub mod hardsubx; +pub mod libccxr_exports; pub mod utils; #[cfg(windows)] diff --git a/src/rust/src/libccxr_exports/mod.rs b/src/rust/src/libccxr_exports/mod.rs new file mode 100644 index 000000000..e365e0fb2 --- /dev/null +++ b/src/rust/src/libccxr_exports/mod.rs @@ -0,0 +1 @@ +//! Provides C-FFI functions that are direct equivalent of functions available in C. From f5da1589351badd985bb29e5b6d4dea24762cd3a Mon Sep 17 00:00:00 2001 From: Ishan Grover <123376573+IshanGrover2004@users.noreply.github.com> Date: Tue, 16 Jul 2024 21:15:24 +0530 Subject: [PATCH 22/27] [FEAT] Add log module in lib_ccxr (#1622) * chore: Add bitflags crate as dependency * feat: Add function to initialize Rust logger using options in C * feat: Add new module `log` * refactor: Add ccx_s_option into list of bindgen struct * feat: Add Initialize logger function * feat: All logging functions & macros * chore: Fix clippy * docs: Mention in Changelogs * chore: format issue fix * fix: Remove activity_header from rust & use initially to print in C * refactor: Remove debugging statements * fix: Add `\n` in info! --- docs/CHANGES.TXT | 1 + src/lib_ccx/activity.c | 11 +- src/lib_ccx/lib_ccx.c | 6 + src/lib_ccx/lib_ccx.h | 4 + src/lib_ccx/utility.c | 1 - src/rust/Cargo.lock | 11 +- src/rust/build.rs | 1 + src/rust/lib_ccxr/Cargo.lock | 9 + src/rust/lib_ccxr/Cargo.toml | 1 + src/rust/lib_ccxr/src/util/log.rs | 572 ++++++++++++++++++++++++++++ src/rust/lib_ccxr/src/util/mod.rs | 2 + src/rust/src/libccxr_exports/mod.rs | 49 +++ 12 files changed, 655 insertions(+), 13 deletions(-) create mode 100644 src/rust/lib_ccxr/src/util/log.rs diff --git a/docs/CHANGES.TXT b/docs/CHANGES.TXT index 39c2104ae..548bc95a4 100644 --- a/docs/CHANGES.TXT +++ b/docs/CHANGES.TXT @@ -1,5 +1,6 @@ 0.95 (to be released) ----------------- +- New: Add log module in lib_ccxr (#1622) - New: Create `lib_ccxr` and `libccxr_exports` (#1621) - Fix: Unexpected behavior of get_write_interval (#1609) - Update: Bump rsmpeg to latest version for ffmpeg bindings (#1600) diff --git a/src/lib_ccx/activity.c b/src/lib_ccx/activity.c index 095c56d6d..1b002fb58 100644 --- a/src/lib_ccx/activity.c +++ b/src/lib_ccx/activity.c @@ -4,7 +4,6 @@ relevant events. */ #include "lib_ccx.h" #include "ccx_common_option.h" -static int credits_shown = 0; unsigned long net_activity_gui = 0; /* Print current progress. For percentage, -1 -> streaming mode */ @@ -129,11 +128,7 @@ void activity_report_data_read(void) void activity_header(void) { - if (!credits_shown) - { - credits_shown = 1; - mprint("CCExtractor %s, Carlos Fernandez Sanz, Volker Quetschke.\n", VERSION); - mprint("Teletext portions taken from Petr Kutalek's telxcc\n"); - mprint("--------------------------------------------------------------------------\n"); - } + mprint("CCExtractor %s, Carlos Fernandez Sanz, Volker Quetschke.\n", VERSION); + mprint("Teletext portions taken from Petr Kutalek's telxcc\n"); + mprint("--------------------------------------------------------------------------\n"); } diff --git a/src/lib_ccx/lib_ccx.c b/src/lib_ccx/lib_ccx.c index 74a0bc88a..14b1b157e 100644 --- a/src/lib_ccx/lib_ccx.c +++ b/src/lib_ccx/lib_ccx.c @@ -93,6 +93,8 @@ struct lib_ccx_ctx *init_libraries(struct ccx_s_options *opt) { int ret = 0; + activity_header(); // Brag about writing it :-) + // Set logging functions for libraries ccx_common_logging.debug_ftn = &dbg_print; ccx_common_logging.debug_mask = opt->debug_mask; @@ -100,6 +102,10 @@ struct lib_ccx_ctx *init_libraries(struct ccx_s_options *opt) ccx_common_logging.log_ftn = &mprint; ccx_common_logging.gui_ftn = &activity_library_process; +#ifndef DISABLE_RUST + ccxr_init_basic_logger(opt); +#endif + struct lib_ccx_ctx *ctx = malloc(sizeof(struct lib_ccx_ctx)); if (!ctx) ccx_common_logging.fatal_ftn(EXIT_NOT_ENOUGH_MEMORY, "init_libraries: Not enough memory allocating lib_ccx_ctx context."); diff --git a/src/lib_ccx/lib_ccx.h b/src/lib_ccx/lib_ccx.h index 92d72e488..3d107826e 100644 --- a/src/lib_ccx/lib_ccx.h +++ b/src/lib_ccx/lib_ccx.h @@ -153,6 +153,10 @@ struct lib_ccx_ctx struct lib_ccx_ctx *init_libraries(struct ccx_s_options *opt); void dinit_libraries( struct lib_ccx_ctx **ctx); +#ifndef DISABLE_RUST +extern void ccxr_init_basic_logger(struct ccx_s_options *opts); +#endif + //ccextractor.c void print_end_msg(void); diff --git a/src/lib_ccx/utility.c b/src/lib_ccx/utility.c index cb3cb6152..e1ef1d7f1 100644 --- a/src/lib_ccx/utility.c +++ b/src/lib_ccx/utility.c @@ -288,7 +288,6 @@ void mprint(const char *fmt, ...) va_list args; if (!ccx_options.messages_target) return; - activity_header(); // Brag about writing it :-) va_start(args, fmt); if (ccx_options.messages_target == CCX_MESSAGES_STDOUT) { diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 9b59367c1..ce5c11dc3 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -65,7 +65,7 @@ version = "0.69.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.6.0", "cexpr", "clang-sys", "itertools", @@ -90,9 +90,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "camino" @@ -280,6 +280,9 @@ dependencies = [ [[package]] name = "lib_ccxr" version = "0.1.0" +dependencies = [ + "bitflags 2.6.0", +] [[package]] name = "libc" @@ -526,7 +529,7 @@ version = "0.38.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7db8590df6dfcd144d22afd1b83b36c21a18d7cbc1dc4bb5295a8712e9eb662" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.6.0", "errno", "libc", "linux-raw-sys", diff --git a/src/rust/build.rs b/src/rust/build.rs index 03e6157f6..6c860c5c1 100644 --- a/src/rust/build.rs +++ b/src/rust/build.rs @@ -26,6 +26,7 @@ fn main() { "lib_cc_decode", "cc_subtitle", "ccx_output_format", + "ccx_s_options", ]); #[cfg(feature = "hardsubx_ocr")] diff --git a/src/rust/lib_ccxr/Cargo.lock b/src/rust/lib_ccxr/Cargo.lock index 7532d4515..79aa1872e 100644 --- a/src/rust/lib_ccxr/Cargo.lock +++ b/src/rust/lib_ccxr/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + [[package]] name = "lib_ccxr" version = "0.1.0" +dependencies = [ + "bitflags", +] diff --git a/src/rust/lib_ccxr/Cargo.toml b/src/rust/lib_ccxr/Cargo.toml index ca3612505..7a8ff30e3 100644 --- a/src/rust/lib_ccxr/Cargo.toml +++ b/src/rust/lib_ccxr/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +bitflags = "2.6.0" [features] default = ["enable_sharing", "wtv_debug", "enable_ffmpeg", "debug", "with_libcurl"] diff --git a/src/rust/lib_ccxr/src/util/log.rs b/src/rust/lib_ccxr/src/util/log.rs new file mode 100644 index 000000000..397f6bb8a --- /dev/null +++ b/src/rust/lib_ccxr/src/util/log.rs @@ -0,0 +1,572 @@ +//! +//! The interface of this module is highly inspired by the famous log crate of rust. +//! +//! The first step before using any of the logging functionality is to setup a logger. This can be +//! done by creating a [`CCExtractorLogger`] and calling [`set_logger`] with it. To gain access to +//! the instance of [`CCExtractorLogger`], [`logger`] or [`logger_mut`] can be used. +//! +//! There are 4 types of logging messages based on its importance and severity denoted by their +//! respective macros. +//! - [`fatal!`] +//! - [`error!`] +//! - [`info!`] +//! - [`debug!`] +//! +//! Hex dumps can be logged for debugging by [`hex_dump`] and [`hex_dump_with_start_idx`]. Communication +//! with the GUI is possible through [`send_gui`]. +//! +//! # Conversion Guide +//! +//! | From | To | +//! |------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------| +//! | `EXIT_*`, `CCX_COMMON_EXIT_*` | [`ExitCause`] | +//! | `CCX_MESSAGES_*` | [`OutputTarget`] | +//! | `CCX_DMT_*`, `ccx_debug_message_types` | [`DebugMessageFlag`] | +//! | `temp_debug`, `ccx_options.debug_mask`, `ccx_options.debug_mask_on_debug` | [`DebugMessageMask`] | +//! | `ccx_options.messages_target`, `temp_debug`, `ccx_options.debug_mask`, `ccx_options.debug_mask_on_debug`, `ccx_options.gui_mode_reports` | [`CCExtractorLogger`] | +//! | `fatal`, `ccx_common_logging.fatal_ftn` | [`fatal!`] | +//! | `mprint`, `ccx_common_logging.log_ftn` | [`info!`] | +//! | `dbg_print`, `ccx_common_logging.debug_ftn` | [`debug!`] | +//! | `activity_library_process`, `ccx_common_logging.gui_ftn` | [`send_gui`] | +//! | `ccx_common_logging_gui` | [`GuiXdsMessage`] | +//! | `dump` | [`hex_dump`] | +//! | `dump` | [`hex_dump_with_start_idx`] | + +use bitflags::bitflags; +use std::fmt::Arguments; +use std::sync::{OnceLock, RwLock, RwLockReadGuard, RwLockWriteGuard}; + +static LOGGER: OnceLock> = OnceLock::new(); + +/// The possible targets for logging messages. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum OutputTarget { + Stdout, + Stderr, + Quiet, +} + +bitflags! { + /// A bitflag for the types of a Debug Message. + /// + /// Each debug message can belong to one or more of these types. The + /// constants of this struct can be used as bitflags for one message to + /// belong to more than one type. + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] + pub struct DebugMessageFlag: u16 { + /// Show information related to parsing the container + const PARSE = 0x1; + /// Show video stream related information + const VIDEO_STREAM = 0x2; + /// Show GOP and PTS timing information + const TIME = 0x4; + /// Show lots of debugging output + const VERBOSE = 0x8; + /// Show CC-608 decoder debug + const DECODER_608 = 0x10; + /// Show CC-708 decoder debug + const DECODER_708 = 0x20; + /// Show XDS decoder debug + const DECODER_XDS = 0x40; + /// Show Caption blocks with FTS timing + const CB_RAW = 0x80; + /// Generic, always displayed even if no debug is selected + const GENERIC_NOTICE = 0x100; + /// Show teletext debug + const TELETEXT = 0x200; + /// Show Program Allocation Table dump + const PAT = 0x400; + /// Show Program Map Table dump + const PMT = 0x800; + /// Show Levenshtein distance calculations + const LEVENSHTEIN = 0x1000; + /// Show DVB debug + const DVB = 0x2000; + /// Dump defective TS packets + const DUMP_DEF = 0x4000; + /// Extracted captions sharing service + #[cfg(feature = "enable_sharing")] + const SHARE = 0x8000; + } +} + +/// All possible causes for crashing the program instantly. Used in `cause` key of [`fatal!`] macro. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum ExitCause { + Ok, + Failure, + NoInputFiles, + TooManyInputFiles, + IncompatibleParameters, + UnableToDetermineFileSize, + MalformedParameter, + ReadError, + NoCaptions, + WithHelp, + NotClassified, + ErrorInCapitalizationFile, + BufferFull, + MissingAsfHeader, + MissingRcwtHeader, + + FileCreationFailed, + Unsupported, + NotEnoughMemory, + Bug, +} + +/// A message to be sent to GUI for XDS. Used in [`send_gui`]. +pub enum GuiXdsMessage<'a> { + ProgramName(&'a str), + ProgramIdNr { + minute: u8, + hour: u8, + date: u8, + month: u8, + }, + ProgramDescription { + line_num: i32, + desc: &'a str, + }, + CallLetters(&'a str), +} + +/// A mask to filter the debug messages based on its type specified by [`DebugMessageFlag`]. +/// +/// This operates on one of the two modes: Normal Mode and Debug Mode. The mask used when in Debug Mode is a superset +/// of the mask used when in Normal Mode. One can switch between the two modes by [`DebugMessageMask::set_debug_mode`]. +#[derive(Debug)] +pub struct DebugMessageMask { + debug_mode: bool, + mask_on_normal: DebugMessageFlag, + mask_on_debug: DebugMessageFlag, +} + +/// A global logger used throughout CCExtractor and stores the settings related to logging. +/// +/// A global logger can be setup up initially using [`set_logger`]. Use the following convenience +/// macros for logging: [`fatal!`], [`error!`], [`info!`] and [`debug!`]. +#[derive(Debug)] +pub struct CCExtractorLogger { + target: OutputTarget, + debug_mask: DebugMessageMask, + gui_mode: bool, +} + +impl DebugMessageMask { + /// Creates a new [`DebugMessageFlag`] given a mask to be used for Normal Mode and an additional mask to be + /// used in Debug Mode. + /// + /// Note that while in Debug Mode, the mask for Normal Mode will still be valid. + /// `extra_mask_on_debug` only specifies additional flags to be set on Debug Mode. + pub const fn new( + mask_on_normal: DebugMessageFlag, + extra_mask_on_debug: DebugMessageFlag, + ) -> DebugMessageMask { + DebugMessageMask { + debug_mode: false, + mask_on_normal, + mask_on_debug: extra_mask_on_debug.union(mask_on_normal), + } + } + + /// Set the mode to Normal or Debug Mode based on `false` or `true` respectively. + pub fn set_debug_mode(&mut self, mode: bool) { + self.debug_mode = mode; + } + + /// Check if the current mode is set to Debug Mode. + pub fn is_debug_mode(&self) -> bool { + self.debug_mode + } + + /// Return the mask according to its mode. + pub fn mask(&self) -> DebugMessageFlag { + if self.debug_mode { + self.mask_on_debug + } else { + self.mask_on_normal + } + } +} + +impl ExitCause { + /// Returns the exit code associated with the cause of the error. + /// + /// The GUI depends on these exit codes. + /// Exit code of 0 means OK as usual. + /// Exit code below 100 means display whatever was output to stderr as a warning. + /// Exit code above or equal to 100 means display whatever was output to stdout as an error. + pub fn exit_code(&self) -> i32 { + match self { + ExitCause::Ok => 0, + ExitCause::Failure => 1, + ExitCause::NoInputFiles => 2, + ExitCause::TooManyInputFiles => 3, + ExitCause::IncompatibleParameters => 4, + ExitCause::UnableToDetermineFileSize => 6, + ExitCause::MalformedParameter => 7, + ExitCause::ReadError => 8, + ExitCause::NoCaptions => 10, + ExitCause::WithHelp => 11, + ExitCause::NotClassified => 300, + ExitCause::ErrorInCapitalizationFile => 501, + ExitCause::BufferFull => 502, + ExitCause::MissingAsfHeader => 1001, + ExitCause::MissingRcwtHeader => 1002, + + ExitCause::FileCreationFailed => 5, + ExitCause::Unsupported => 9, + ExitCause::NotEnoughMemory => 500, + ExitCause::Bug => 1000, + } + } +} + +impl<'a> CCExtractorLogger { + /// Returns a new instance of CCExtractorLogger with the provided settings. + /// + /// `gui_mode` is used to determine if the log massages are intercepted by a GUI. + /// `target` specifies the location for printing the log messages. + /// `debug_mask` is used to filter debug messages based on its type. + pub const fn new( + target: OutputTarget, + debug_mask: DebugMessageMask, + gui_mode: bool, + ) -> CCExtractorLogger { + CCExtractorLogger { + target, + debug_mask, + gui_mode, + } + } + + /// Set the mode to Normal or Debug Mode based on `false` or `true` respectively for the + /// underlying [`DebugMessageMask`]. + /// + /// This method switches the mask used for filtering debug messages. + /// Similar to [`DebugMessageMask::set_debug_mode`]. + pub fn set_debug_mode(&mut self, mode: bool) { + self.debug_mask.set_debug_mode(mode) + } + + /// Check if the current mode is set to Debug Mode. + /// + /// Similar to [`DebugMessageMask::is_debug_mode`]. + pub fn is_debug_mode(&self) -> bool { + self.debug_mask.is_debug_mode() + } + + /// Returns the currently set target for logging messages. + pub fn target(&self) -> OutputTarget { + self.target + } + + /// Check if the messages are intercepted by GUI. + pub fn is_gui_mode(&self) -> bool { + self.gui_mode + } + + fn print(&self, args: &Arguments<'a>) { + match &self.target { + OutputTarget::Stdout => print!("{}", args), + OutputTarget::Stderr => eprint!("{}", args), + OutputTarget::Quiet => {} + } + } + + /// Log a fatal error message. Use [`fatal!`] instead. + /// + /// Used for logging errors dangerous enough to crash the program instantly. + pub fn log_fatal(&self, exit_cause: ExitCause, args: &Arguments<'a>) -> ! { + self.log_error(args); + info!("Issues? Open a ticket here\n"); + info!("https://github.com/CCExtractor/ccextractor/issues\n"); + std::process::exit(exit_cause.exit_code()) + } + + /// Log an error message. Use [`error!`] instead. + /// + /// Used for logging general errors occuring in the program. + pub fn log_error(&self, args: &Arguments<'a>) { + if self.gui_mode { + eprint!("###MESSAGE#") + } else { + eprint!("\rError: ") + } + + eprintln!("{}", args); + } + + /// Log an informational message. Use [`info!`] instead. + /// + /// Used for logging extra information about the execution of the program. + pub fn log_info(&self, args: &Arguments<'a>) { + if self.target == OutputTarget::Quiet { + return; + } + + self.print(args); + } + + /// Log a debug message. Use [`debug!`] instead. + /// + /// Used for logging debug messages throughout the program. + pub fn log_debug(&self, message_type: DebugMessageFlag, args: &Arguments<'a>) { + if self.debug_mask.mask().intersects(message_type) { + self.print(args); + } + } + + /// Send a message to GUI. Use [`send_gui`] instead. + /// + /// Used for sending information related to XDS to the GUI. + pub fn send_gui(&self, message_type: GuiXdsMessage) { + if self.gui_mode { + match message_type { + GuiXdsMessage::ProgramName(program_name) => { + eprintln!("###XDSPROGRAMNAME#{}", program_name) + } + GuiXdsMessage::ProgramIdNr { + minute, + hour, + date, + month, + } => eprintln!( + "###XDSPROGRAMIDENTIFICATIONNUMBER#{}#{}#{}#{}", + minute, hour, date, month + ), + GuiXdsMessage::ProgramDescription { line_num, desc } => { + eprintln!("###XDSPROGRAMDESC#{}#{}", line_num, desc) + } + GuiXdsMessage::CallLetters(current_letters) => { + eprintln!("###XDSNETWORKCALLLETTERS#{}", current_letters) + } + } + } + } + + /// Log a hex dump which is helpful for debugging purposes. + /// Use [`hex_dump`] or [`hex_dump_with_start_idx`] instead. + /// + /// Setting `clear_high_bit` to true will ignore the highest bit whien displaying the + /// characters. This makes visual CC inspection easier since the highest bit is usually used + /// as a parity bit. + /// + /// The output will contain byte numbers which can be made to start from any number using + /// `start_idx`. This is usually `0`. + pub fn log_hex_dump( + &self, + message_type: DebugMessageFlag, + data: &[u8], + clear_high_bit: bool, + start_idx: usize, + ) { + if !self.debug_mask.mask().intersects(message_type) { + return; + } + let chunked_data = data.chunks(16); + + for (id, chunk) in chunked_data.enumerate() { + self.print(&format_args!("{:05} | ", id * 16 + start_idx)); + for x in chunk { + self.print(&format_args!("{:02X} ", x)); + } + + for _ in 0..(16 - chunk.len()) { + self.print(&format_args!(" ")); + } + + self.print(&format_args!(" | ")); + + for x in chunk { + let c = if x >= &b' ' { + // 0x7F < remove high bit, convenient for visual CC inspection + x & if clear_high_bit { 0x7F } else { 0xFF } + } else { + b' ' + }; + + self.print(&format_args!("{}", c as char)); + } + + self.print(&format_args!("\n")); + } + } +} + +/// Setup the global logger. +/// +/// This function can only be called once throught the execution of program. The logger can then be +/// accessed by [`logger`] and [`logger_mut`]. +pub fn set_logger(logger: CCExtractorLogger) -> Result<(), CCExtractorLogger> { + LOGGER + .set(logger.into()) + .map_err(|x| x.into_inner().unwrap()) +} + +/// Get an immutable instance of the global logger. +/// +/// This function will return [`None`] if the logger is not setup initially by [`set_logger`] or if +/// the underlying RwLock fails to generate a read lock. +/// +/// Use [`logger_mut`] to get a mutable instance. +pub fn logger() -> Option> { + LOGGER.get()?.read().ok() +} + +/// Get a mutable instance of the global logger. +/// +/// This function will return [`None`] if the logger is not setup initially by [`set_logger`] or if +/// the underlying RwLock fails to generate a write lock. +/// +/// Use [`logger`] to get an immutable instance. +pub fn logger_mut() -> Option> { + LOGGER.get()?.write().ok() +} + +/// Log a fatal error message. +/// +/// Used for logging errors dangerous enough to crash the program instantly. This macro does not +/// return (i.e. it returns `!`). A logger needs to be setup initially by [`set_logger`]. +/// +/// # Usage +/// This macro requires an [`ExitCause`] which provides the appropriate exit codes for shutting +/// down program. This is provided using a key called `cause` which comes before the `;`. After +/// `;`, the arguments works the same as a [`println!`] macro. +/// +/// # Examples +/// ```no_run +/// # use lib_ccxr::util::log::*; +/// # let actual = 2; +/// # let required = 1; +/// fatal!( +/// cause = ExitCause::TooManyInputFiles; +/// "{} input files were provided but only {} were needed", actual, required +/// ); +/// ``` +#[macro_export] +macro_rules! fatal { + (cause = $exit_cause:expr; $($args:expr),*) => { + $crate::util::log::logger().expect("Logger is not yet initialized") + .log_fatal($exit_cause, &format_args!($($args),*)) + }; +} + +/// Log an error message. +/// +/// Used for logging general errors occuring in the program. A logger needs to be setup +/// initially by [`set_logger`]. +/// +/// # Usage +/// The arguments works the same as a [`println!`] macro. +/// +/// # Examples +/// ```no_run +/// # use lib_ccxr::util::log::*; +/// # let missing_blocks = 2; +/// error!("missing {} additional blocks", missing_blocks); +/// ``` +#[macro_export] +macro_rules! error { + ($($args:expr),*) => { + $crate::util::log::logger().expect("Logger is not yet initialized") + .log_error(&format_args!($($args),*)) + } +} + +/// Log an informational message. +/// +/// Used for logging extra information about the execution of the program. A logger needs to be +/// setup initially by [`set_logger`]. +/// +/// # Usage +/// The arguments works the same as a [`println!`] macro. +/// +/// # Examples +/// ```no_run +/// # use lib_ccxr::util::log::*; +/// info!("Processing the header section\n"); +/// ``` +#[macro_export] +macro_rules! info { + ($($args:expr),*) => { + $crate::util::log::logger().expect("Logger is not yet initialized") + .log_info(&format_args!($($args),*)) + }; +} + +/// Log a debug message. +/// +/// Used for logging debug messages throughout the program. A logger needs to be setup initially +/// by [`set_logger`]. +/// +/// # Usage +/// This macro requires an [`DebugMessageFlag`] which represents the type of debug message. It is +/// used for filtering the messages. This is provided using a key called `msg_type` which comes +/// before the `;`. After `;`, the arguments works the same as a [`println!`] macro. +/// +/// # Examples +/// ```no_run +/// # use lib_ccxr::util::log::*; +/// # let byte1 = 23u8; +/// # let byte2 = 45u8; +/// debug!( +/// msg_type = DebugMessageFlag::DECODER_708; +/// "Packet Start with contents {} {}", byte1, byte2 +/// ); +/// ``` +#[macro_export] +macro_rules! debug { + (msg_type = $msg_flag:expr; $($args:expr),*) => { + $crate::util::log::logger().expect("Logger is not yet initialized") + .log_debug($msg_flag, &format_args!($($args),*)) + }; +} + +pub use debug; +pub use error; +pub use fatal; +pub use info; + +/// Log a hex dump which is helpful for debugging purposes. +/// +/// Setting `clear_high_bit` to true will ignore the highest bit whien displaying the +/// characters. This makes visual CC inspection easier since the highest bit is usually used +/// as a parity bit. +/// +/// The byte numbers start from `0` by default. Use [`hex_dump_with_start_idx`] if a +/// different starting index is required. +pub fn hex_dump(message_type: DebugMessageFlag, data: &[u8], clear_high_bit: bool) { + logger() + .expect("Logger is not yet initialized") + .log_hex_dump(message_type, data, clear_high_bit, 0) +} + +/// Log a hex dump which is helpful for debugging purposes. +/// +/// Setting `clear_high_bit` to true will ignore the highest bit whien displaying the +/// characters. This makes visual CC inspection easier since the highest bit is usually used +/// as a parity bit. +/// +/// The output will contain byte numbers which can be made to start from any number using +/// `start_idx`. This is usually `0`. +pub fn hex_dump_with_start_idx( + message_type: DebugMessageFlag, + data: &[u8], + clear_high_bit: bool, + start_idx: usize, +) { + logger() + .expect("Logger is not yet initialized") + .log_hex_dump(message_type, data, clear_high_bit, start_idx) +} + +/// Send a message to GUI. +/// +/// Used for sending information related to XDS to the GUI. +pub fn send_gui(message: GuiXdsMessage) { + logger() + .expect("Logger is not yet initialized") + .send_gui(message) +} diff --git a/src/rust/lib_ccxr/src/util/mod.rs b/src/rust/lib_ccxr/src/util/mod.rs index daf5935ac..504f17e26 100644 --- a/src/rust/lib_ccxr/src/util/mod.rs +++ b/src/rust/lib_ccxr/src/util/mod.rs @@ -1 +1,3 @@ //! Provides basic utilities used throughout the program. + +pub mod log; diff --git a/src/rust/src/libccxr_exports/mod.rs b/src/rust/src/libccxr_exports/mod.rs index e365e0fb2..60030671e 100644 --- a/src/rust/src/libccxr_exports/mod.rs +++ b/src/rust/src/libccxr_exports/mod.rs @@ -1 +1,50 @@ //! Provides C-FFI functions that are direct equivalent of functions available in C. + +use crate::ccx_s_options; +use core::panic; +use lib_ccxr::util::log::*; +use std::convert::TryInto; + +/// Initializes the logger at the rust side. +/// +/// # Safety +/// +/// `ccx_options` must not be null and must initialized properly before calling this function. +#[no_mangle] +pub unsafe extern "C" fn ccxr_init_basic_logger(ccx_options: *const ccx_s_options) { + if ccx_options.is_null() { + panic!("ccx_s_options must not be null"); + } + + let debug_mask = DebugMessageFlag::from_bits( + (*ccx_options) + .debug_mask + .try_into() + .expect("Failed to convert debug_mask to an unsigned integer"), + ) + .expect("Failed to convert debug_mask to a DebugMessageFlag"); + + let debug_mask_on_debug = DebugMessageFlag::from_bits( + (*ccx_options) + .debug_mask_on_debug + .try_into() + .expect("Failed to convert debug_mask_on_debug to an unsigned integer"), + ) + .expect("Failed to convert debug_mask_on_debug to a DebugMessageFlag"); + + let mask = DebugMessageMask::new(debug_mask, debug_mask_on_debug); + let gui_mode_reports = unsafe { *ccx_options }.gui_mode_reports != 0; + let messages_target = match unsafe { *ccx_options }.messages_target { + 0 => OutputTarget::Stdout, + 1 => OutputTarget::Stderr, + 2 => OutputTarget::Quiet, + _ => panic!("incorrect value for messages_target"), + }; + + set_logger(CCExtractorLogger::new( + messages_target, + mask, + gui_mode_reports, + )) + .expect("Failed to initialize and setup the logger"); +} From cf9c9dde53f0e0bcff8c76642e49360c47f9a9ca Mon Sep 17 00:00:00 2001 From: Ishan Grover <123376573+IshanGrover2004@users.noreply.github.com> Date: Tue, 16 Jul 2024 21:42:03 +0530 Subject: [PATCH 23/27] [FEAT] Add constants module in `lib_ccxr` (#1624) * feat: Add common module common module is made for all `ccx_common_*` files * feat: Add constants module within common module Used to have all constants enums listed in ccx_common_constants C file * feat: Add all constants, enums in rust equivaleent to `ccx_common_constansts` C file * docs: Mention in Changelogs * docs: Add more conversion data --- docs/CHANGES.TXT | 1 + src/rust/lib_ccxr/src/common/constants.rs | 617 ++++++++++++++++++++++ src/rust/lib_ccxr/src/common/mod.rs | 3 + src/rust/lib_ccxr/src/lib.rs | 1 + 4 files changed, 622 insertions(+) create mode 100644 src/rust/lib_ccxr/src/common/constants.rs create mode 100644 src/rust/lib_ccxr/src/common/mod.rs diff --git a/docs/CHANGES.TXT b/docs/CHANGES.TXT index 548bc95a4..6e362884d 100644 --- a/docs/CHANGES.TXT +++ b/docs/CHANGES.TXT @@ -1,5 +1,6 @@ 0.95 (to be released) ----------------- +- New: [FEAT] Add constants module in lib_ccxr (#1624) - New: Add log module in lib_ccxr (#1622) - New: Create `lib_ccxr` and `libccxr_exports` (#1621) - Fix: Unexpected behavior of get_write_interval (#1609) diff --git a/src/rust/lib_ccxr/src/common/constants.rs b/src/rust/lib_ccxr/src/common/constants.rs new file mode 100644 index 000000000..82237bafc --- /dev/null +++ b/src/rust/lib_ccxr/src/common/constants.rs @@ -0,0 +1,617 @@ +//! Provides common constant types throughout the codebase. +//! Rust equivalent for `ccx_common_constants.c` file in C. +//! +//! # Conversion Guide +//! +//! | From | To | +//! |--------------------------------|--------------------------------------------| +//! | `ccx_avc_nal_types` | [`AvcNalType`] | +//! | `ccx_stream_type` | [`StreamType`] | +//! | `ccx_mpeg_descriptor` | [`MpegDescriptor`] | +//! | `ccx_datasource` | [`DataSource`] | +//! | `ccx_output_format` | [`OutputFormat`] | +//! | `ccx_stream_mode_enum` | [`StreamMode`] | +//! | `ccx_bufferdata_type` | [`BufferdataType`] | +//! | `ccx_frame_type` | [`FrameType`] | +//! | `ccx_code_type` | [`Codec`] | +//! | `cdp_section_type` | [`CdpSectionType`] | +//! | `cc_types[4]` | [`CCTypes`] | +//! | `CCX_TXT_*` macros | [`CcxTxt`] | +//! | `language[NB_LANGUAGE]` | [`Language`] | +//! | `DEF_VAL_*` macros | [`CreditTiming`] | +//! | `IS_FEASIBLE` macro | [`Codec::is_feasible`] | +//! | `IS_VALID_TELETEXT_DESC` macro | [`MpegDescriptor::is_valid_teletext_desc`] | + +use std::ffi::OsStr; + +// RCWT header (11 bytes): +// byte(s) value description (All values below are hex numbers, not +// actual numbers or values +// 0-2 CCCCED magic number, for Closed Caption CC Extractor Data +// 3 CC Creating program. Legal values: CC = CC Extractor +// 4-5 0050 Program version number +// 6-7 0001 File format version +// 8-10 000000 Padding, required :-) +pub static mut RCWT_HEADER: [u8; 11] = [0xCC, 0xCC, 0xED, 0xCC, 0x00, 0x50, 0, 1, 0, 0, 0]; + +pub const BROADCAST_HEADER: [u8; 4] = [0xff, 0xff, 0xff, 0xff]; +pub const LITTLE_ENDIAN_BOM: [u8; 2] = [0xff, 0xfe]; +pub const UTF8_BOM: [u8; 3] = [0xef, 0xbb, 0xbf]; +pub const DVD_HEADER: [u8; 8] = [0x00, 0x00, 0x01, 0xb2, 0x43, 0x43, 0x01, 0xf8]; +pub const LC1: [u8; 1] = [0x8a]; +pub const LC2: [u8; 1] = [0x8f]; +pub const LC3: [u8; 2] = [0x16, 0xfe]; +pub const LC4: [u8; 2] = [0x1e, 0xfe]; +pub const LC5: [u8; 1] = [0xff]; +pub const LC6: [u8; 1] = [0xfe]; + +pub const FRAMERATES_VALUES: [f64; 16] = [ + 0.0, + 24000.0 / 1001.0, // 23.976 + 24.0, + 25.0, + 30000.0 / 1001.0, // 29.97 + 30.0, + 50.0, + 60000.0 / 1001.0, // 59.94 + 60.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, +]; + +pub const FRAMERATES_TYPES: [&str; 16] = [ + "00 - forbidden", + "01 - 23.976", + "02 - 24", + "03 - 25", + "04 - 29.97", + "05 - 30", + "06 - 50", + "07 - 59.94", + "08 - 60", + "09 - reserved", + "10 - reserved", + "11 - reserved", + "12 - reserved", + "13 - reserved", + "14 - reserved", + "15 - reserved", +]; + +pub const ASPECT_RATIO_TYPES: [&str; 16] = [ + "00 - forbidden", + "01 - 1:1", + "02 - 4:3", + "03 - 16:9", + "04 - 2.21:1", + "05 - reserved", + "06 - reserved", + "07 - reserved", + "08 - reserved", + "09 - reserved", + "10 - reserved", + "11 - reserved", + "12 - reserved", + "13 - reserved", + "14 - reserved", + "15 - reserved", +]; + +pub const PICT_TYPES: [&str; 8] = [ + "00 - illegal (0)", + "01 - I", + "02 - P", + "03 - B", + "04 - illegal (D)", + "05 - illegal (5)", + "06 - illegal (6)", + "07 - illegal (7)", +]; + +pub const SLICE_TYPES: [&str; 10] = [ + "0 - P", "1 - B", "2 - I", "3 - SP", "4 - SI", "5 - P", "6 - B", "7 - I", "8 - SP", "9 - SI", +]; + +pub const ONEPASS: usize = 120; // Bytes we can always look ahead without going out of limits +pub const BUFSIZE: usize = 2048 * 1024 + ONEPASS; // 2 Mb plus the safety pass +pub const MAX_CLOSED_CAPTION_DATA_PER_PICTURE: usize = 32; +pub const EIA_708_BUFFER_LENGTH: usize = 2048; // TODO: Find out what the real limit is +pub const TS_PACKET_PAYLOAD_LENGTH: usize = 184; // From specs +pub const SUBLINESIZE: usize = 2048; // Max. length of a .srt line - TODO: Get rid of this +pub const STARTBYTESLENGTH: usize = 1024 * 1024; +pub const UTF8_MAX_BYTES: usize = 6; +pub const XMLRPC_CHUNK_SIZE: usize = 64 * 1024; // 64 Kb per chunk, to avoid too many realloc() + +// AVC NAL types +pub enum AvcNalType { + Unspecified0 = 0, + CodedSliceNonIdrPicture1 = 1, + CodedSlicePartitionA = 2, + CodedSlicePartitionB = 3, + CodedSlicePartitionC = 4, + CodedSliceIdrPicture = 5, + Sei = 6, + SequenceParameterSet7 = 7, + PictureParameterSet = 8, + AccessUnitDelimiter9 = 9, + EndOfSequence = 10, + EndOfStream = 11, + FillerData = 12, + SequenceParameterSetExtension = 13, + PrefixNalUnit = 14, + SubsetSequenceParameterSet = 15, + Reserved16 = 16, + Reserved17 = 17, + Reserved18 = 18, + CodedSliceAuxiliaryPicture = 19, + CodedSliceExtension = 20, + Reserved21 = 21, + Reserved22 = 22, + Reserved23 = 23, + Unspecified24 = 24, + Unspecified25 = 25, + Unspecified26 = 26, + Unspecified27 = 27, + Unspecified28 = 28, + Unspecified29 = 29, + Unspecified30 = 30, + Unspecified31 = 31, +} + +// MPEG-2 TS stream types +pub enum StreamType { + Unknownstream = 0, + /* + The later constants are defined by MPEG-TS standard + Explore at: https://exiftool.org/TagNames/M2TS.html + */ + VideoMpeg1 = 0x01, + VideoMpeg2 = 0x02, + AudioMpeg1 = 0x03, + AudioMpeg2 = 0x04, + PrivateTableMpeg2 = 0x05, + PrivateMpeg2 = 0x06, + MhegPackets = 0x07, + Mpeg2AnnexADsmCc = 0x08, + ItuTH222_1 = 0x09, + IsoIec13818_6TypeA = 0x0a, + IsoIec13818_6TypeB = 0x0b, + IsoIec13818_6TypeC = 0x0c, + IsoIec13818_6TypeD = 0x0d, + AudioAac = 0x0f, + VideoMpeg4 = 0x10, + VideoH264 = 0x1b, + PrivateUserMpeg2 = 0x80, + AudioAc3 = 0x81, + AudioHdmvDts = 0x82, + AudioDts = 0x8a, +} + +pub enum MpegDescriptor { + /* + The later constants are defined by ETSI EN 300 468 standard + Explore at: https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.11.01_60/en_300468v011101p.pdf + */ + Registration = 0x05, + DataStreamAlignment = 0x06, + Iso639Language = 0x0a, + VbiDataDescriptor = 0x45, + VbiTeletextDescriptor = 0x46, + TeletextDescriptor = 0x56, + DvbSubtitle = 0x59, + /* User defined */ + CaptionService = 0x86, + DataComp = 0xfd, // Consider to change DESC to DSC +} + +pub enum DataSource { + File, + Stdin, + Network, + Tcp, +} + +/// An enum of all the available formats for the subtitle output. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum OutputFormat { + Raw, + Srt, + Sami, + Transcript, + Rcwt, + Null, + SmpteTt, + SpuPng, + DvdRaw, // See -d at http://www.theneitherworld.com/mcpoodle/SCC_TOOLS/DOCS/SCC_TOOLS.HTML#CCExtract + WebVtt, + SimpleXml, + G608, + Curl, + Ssa, + Mcc, + Scc, + Ccd, +} + +pub enum StreamMode { + ElementaryOrNotFound = 0, + Transport = 1, + Program = 2, + Asf = 3, + McpoodlesRaw = 4, + Rcwt = 5, // Raw Captions With Time, not used yet. + Myth = 6, // Use the myth loop + Mp4 = 7, // MP4, ISO- + #[cfg(feature = "wtv_debug")] + HexDump = 8, // Hexadecimal dump generated by wtvccdump + Wtv = 9, + #[cfg(feature = "enable_ffmpeg")] + Ffmpeg = 10, + Gxf = 11, + Mkv = 12, + Mxf = 13, + Autodetect = 16, +} + +pub enum BufferdataType { + Unknown, + Pes, + Raw, + H264, + Hauppage, + Teletext, + PrivateMpeg2Cc, + DvbSubtitle, + IsdbSubtitle, + /* Buffer where cc data contain 3 byte cc_valid ccdata 1 ccdata 2 */ + RawType, + DvdSubtitle, +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum FrameType { + ResetOrUnknown, + IFrame, + PFrame, + BFrame, + DFrame, +} + +#[derive(PartialEq, Eq)] +pub enum Codec { + Any, + Teletext, + Dvb, + IsdbCc, + AtscCc, + None, +} + +/// Caption Distribution Packet +pub enum CdpSectionType { + /* + The later constants are defined by SMPTE ST 334 + Purchase for 80$ at: https://ieeexplore.ieee.org/document/8255806 + */ + Data = 0x72, + SvcInfo = 0x73, + Footer = 0x74, +} + +pub enum CCTypes { + NtscCCF1, + NtscCCF2, + DtvccPacketData, + DtvccPacketStart, +} + +pub enum CcxTxt { + Forbidden = 0, // Ignore teletext packets + AutoNotYetFound = 1, + InUse = 2, // Positive auto-detected, or forced, etc +} + +pub enum Language { + Und, // Undefined + Eng, + Afr, + Amh, + Ara, + Asm, + Aze, + Bel, + Ben, + Bod, + Bos, + Bul, + Cat, + Ceb, + Ces, + Chs, + Chi, + Chr, + Cym, + Dan, + Deu, + Dzo, + Ell, + Enm, + Epo, + Equ, + Est, + Eus, + Fas, + Fin, + Fra, + Frk, + Frm, + Gle, + Glg, + Grc, + Guj, + Hat, + Heb, + Hin, + Hrv, + Hun, + Iku, + Ind, + Isl, + Ita, + Jav, + Jpn, + Kan, + Kat, + Kaz, + Khm, + Kir, + Kor, + Kur, + Lao, + Lat, + Lav, + Lit, + Mal, + Mar, + Mkd, + Mlt, + Msa, + Mya, + Nep, + Nld, + Nor, + Ori, + Osd, + Pan, + Pol, + Por, + Pus, + Ron, + Rus, + San, + Sin, + Slk, + Slv, + Spa, + Sqi, + Srp, + Swa, + Swe, + Syr, + Tam, + Tel, + Tgk, + Tgl, + Tha, + Tir, + Tur, + Uig, + Ukr, + Urd, + Uzb, + Vie, + Yid, +} + +pub enum CreditTiming { + StartCreditsNotBefore, + StartCreditsNotAfter, + StartCreditsForAtLeast, + StartCreditsForAtMost, + EndCreditsForAtLeast, + EndCreditsForAtMost, +} + +impl OutputFormat { + /// Returns the file extension for the output format if it is a file based format. + pub fn file_extension(&self) -> Option<&OsStr> { + match self { + OutputFormat::Raw => Some(OsStr::new(".raw")), + OutputFormat::Srt => Some(OsStr::new(".srt")), + OutputFormat::Sami => Some(OsStr::new(".smi")), + OutputFormat::Transcript => Some(OsStr::new(".txt")), + OutputFormat::Rcwt => Some(OsStr::new(".bin")), + OutputFormat::Null => None, + OutputFormat::SmpteTt => Some(OsStr::new(".ttml")), + OutputFormat::SpuPng => Some(OsStr::new(".xml")), + OutputFormat::DvdRaw => Some(OsStr::new(".dvdraw")), + OutputFormat::WebVtt => Some(OsStr::new(".vtt")), + OutputFormat::SimpleXml => Some(OsStr::new(".xml")), + OutputFormat::G608 => Some(OsStr::new(".g608")), + OutputFormat::Curl => None, + OutputFormat::Ssa => Some(OsStr::new(".ass")), + OutputFormat::Mcc => Some(OsStr::new(".mcc")), + OutputFormat::Scc => Some(OsStr::new(".scc")), + OutputFormat::Ccd => Some(OsStr::new(".ccd")), + } + } +} + +impl Codec { + /// Determines whether a specific subtitle codec type should be parsed. + /// + /// # Arguments + /// + /// * `user_selected` - The codec selected by the user to be searched in all elementary streams. + /// * `user_not_selected` - The codec selected by the user not to be parsed. + /// * `feasible` - The codec being tested for feasibility to parse. + /// + /// # Returns + /// + /// Returns `true` if the codec should be parsed, `false` otherwise. + /// + /// # Description + /// + /// This function is used when you want to find out whether you should parse a specific + /// subtitle codec type or not. We ignore the stream if it's not selected, as setting + /// a stream as both selected and not selected doesn't make sense. + pub fn is_feasible(user_selected: &Codec, user_not_selected: &Codec, feasible: &Codec) -> bool { + (*user_selected == Codec::Any && user_not_selected != feasible) || user_selected == feasible + } +} + +impl MpegDescriptor { + pub fn is_valid_teletext_desc(&self) -> bool { + matches!( + self, + MpegDescriptor::VbiDataDescriptor + | MpegDescriptor::VbiTeletextDescriptor + | MpegDescriptor::TeletextDescriptor + ) + } +} + +impl CCTypes { + pub fn to_str(&self) -> &'static str { + match self { + CCTypes::NtscCCF1 => "NTSC line 21 field 1 closed captions", + CCTypes::NtscCCF2 => "NTSC line 21 field 2 closed captions", + CCTypes::DtvccPacketData => "DTVCC Channel Packet Data", + CCTypes::DtvccPacketStart => "DTVCC Channel Packet Start", + } + } +} + +impl CreditTiming { + pub fn value(&self) -> &str { + match self { + CreditTiming::StartCreditsNotBefore => "0", + CreditTiming::StartCreditsNotAfter => "5:00", + CreditTiming::StartCreditsForAtLeast => "2", + CreditTiming::StartCreditsForAtMost => "5", + CreditTiming::EndCreditsForAtLeast => "2", + CreditTiming::EndCreditsForAtMost => "5", + } + } +} + +impl Language { + pub fn to_str(&self) -> &'static str { + match self { + Language::Und => "und", // Undefined + Language::Eng => "eng", + Language::Afr => "afr", + Language::Amh => "amh", + Language::Ara => "ara", + Language::Asm => "asm", + Language::Aze => "aze", + Language::Bel => "bel", + Language::Ben => "ben", + Language::Bod => "bod", + Language::Bos => "bos", + Language::Bul => "bul", + Language::Cat => "cat", + Language::Ceb => "ceb", + Language::Ces => "ces", + Language::Chs => "chs", + Language::Chi => "chi", + Language::Chr => "chr", + Language::Cym => "cym", + Language::Dan => "dan", + Language::Deu => "deu", + Language::Dzo => "dzo", + Language::Ell => "ell", + Language::Enm => "enm", + Language::Epo => "epo", + Language::Equ => "equ", + Language::Est => "est", + Language::Eus => "eus", + Language::Fas => "fas", + Language::Fin => "fin", + Language::Fra => "fra", + Language::Frk => "frk", + Language::Frm => "frm", + Language::Gle => "gle", + Language::Glg => "glg", + Language::Grc => "grc", + Language::Guj => "guj", + Language::Hat => "hat", + Language::Heb => "heb", + Language::Hin => "hin", + Language::Hrv => "hrv", + Language::Hun => "hun", + Language::Iku => "iku", + Language::Ind => "ind", + Language::Isl => "isl", + Language::Ita => "ita", + Language::Jav => "jav", + Language::Jpn => "jpn", + Language::Kan => "kan", + Language::Kat => "kat", + Language::Kaz => "kaz", + Language::Khm => "khm", + Language::Kir => "kir", + Language::Kor => "kor", + Language::Kur => "kur", + Language::Lao => "lao", + Language::Lat => "lat", + Language::Lav => "lav", + Language::Lit => "lit", + Language::Mal => "mal", + Language::Mar => "mar", + Language::Mkd => "mkd", + Language::Mlt => "mlt", + Language::Msa => "msa", + Language::Mya => "mya", + Language::Nep => "nep", + Language::Nld => "nld", + Language::Nor => "nor", + Language::Ori => "ori", + Language::Osd => "osd", + Language::Pan => "pan", + Language::Pol => "pol", + Language::Por => "por", + Language::Pus => "pus", + Language::Ron => "ron", + Language::Rus => "rus", + Language::San => "san", + Language::Sin => "sin", + Language::Slk => "slk", + Language::Slv => "slv", + Language::Spa => "spa", + Language::Sqi => "sqi", + Language::Srp => "srp", + Language::Swa => "swa", + Language::Swe => "swe", + Language::Syr => "syr", + Language::Tam => "tam", + Language::Tel => "tel", + Language::Tgk => "tgk", + Language::Tgl => "tgl", + Language::Tha => "tha", + Language::Tir => "tir", + Language::Tur => "tur", + Language::Uig => "uig", + Language::Ukr => "ukr", + Language::Urd => "urd", + Language::Uzb => "uzb", + Language::Vie => "vie", + Language::Yid => "yid", + } + } +} diff --git a/src/rust/lib_ccxr/src/common/mod.rs b/src/rust/lib_ccxr/src/common/mod.rs new file mode 100644 index 000000000..7976d653e --- /dev/null +++ b/src/rust/lib_ccxr/src/common/mod.rs @@ -0,0 +1,3 @@ +//! Provides common types throughout the codebase. + +pub mod constants; diff --git a/src/rust/lib_ccxr/src/lib.rs b/src/rust/lib_ccxr/src/lib.rs index 812d1edf2..45ee8e79c 100644 --- a/src/rust/lib_ccxr/src/lib.rs +++ b/src/rust/lib_ccxr/src/lib.rs @@ -1 +1,2 @@ +pub mod common; pub mod util; From 8e4c07ed972fa73ef76949f18f1e7467aa5b2566 Mon Sep 17 00:00:00 2001 From: Ishan Grover <123376573+IshanGrover2004@users.noreply.github.com> Date: Tue, 16 Jul 2024 23:30:15 +0530 Subject: [PATCH 24/27] [FEAT] Add bits and levenshtein module in `lib_ccxr` (#1627) * feat: Add 2 new modules * feat: Add `levenshtein` module & code * feat: Add `bits` module & code * feat: Add `extern "C"` function which are equivalent in C-RUST * feat: Call extern ccxr_ functions in C code * docs: Mention in Changelogs --- docs/CHANGES.TXT | 1 + src/lib_ccx/utility.c | 9 + src/lib_ccx/utility.h | 6 + src/rust/lib_ccxr/src/util/bits.rs | 224 ++++++++++++++++++++++ src/rust/lib_ccxr/src/util/levenshtein.rs | 39 ++++ src/rust/lib_ccxr/src/util/mod.rs | 2 + src/rust/src/libccxr_exports/mod.rs | 64 ++++++- 7 files changed, 344 insertions(+), 1 deletion(-) create mode 100644 src/rust/lib_ccxr/src/util/bits.rs create mode 100644 src/rust/lib_ccxr/src/util/levenshtein.rs diff --git a/docs/CHANGES.TXT b/docs/CHANGES.TXT index 6e362884d..9897aae4e 100644 --- a/docs/CHANGES.TXT +++ b/docs/CHANGES.TXT @@ -1,5 +1,6 @@ 0.95 (to be released) ----------------- +- New: Add bits and levenshtein module in lib_ccxr (#1627) - New: [FEAT] Add constants module in lib_ccxr (#1624) - New: Add log module in lib_ccxr (#1622) - New: Create `lib_ccxr` and `libccxr_exports` (#1621) diff --git a/src/lib_ccx/utility.c b/src/lib_ccx/utility.c index e1ef1d7f1..2be551f5c 100644 --- a/src/lib_ccx/utility.c +++ b/src/lib_ccx/utility.c @@ -77,6 +77,9 @@ static uint32_t crc32_table[] = { int verify_crc32(uint8_t *buf, int len) { +#ifndef DISABLE_RUST + return ccxr_verify_crc32(buf, len); +#endif /* ifndef DISABLE_RUST */ int i = 0; int32_t crc = -1; for (i = 0; i < len; i++) @@ -151,6 +154,9 @@ void timestamp_to_vtttime(uint64_t timestamp, char *buffer) int levenshtein_dist(const uint64_t *s1, const uint64_t *s2, unsigned s1len, unsigned s2len) { +#ifndef DISABLE_RUST + return ccxr_levenshtein_dist(s1, s2, s1len, s2len); +#endif unsigned int x, y, v, lastdiag, olddiag; unsigned int *column = (unsigned *)malloc((s1len + 1) * sizeof(unsigned int)); for (y = 1; y <= s1len; y++) @@ -172,6 +178,9 @@ int levenshtein_dist(const uint64_t *s1, const uint64_t *s2, unsigned s1len, uns int levenshtein_dist_char(const char *s1, const char *s2, unsigned s1len, unsigned s2len) { +#ifndef DISABLE_RUST + return ccxr_levenshtein_dist_char(s1, s2, s1len, s2len); +#endif unsigned int x, y, v, lastdiag, olddiag; unsigned int *column = (unsigned *)malloc((s1len + 1) * sizeof(unsigned int)); for (y = 1; y <= s1len; y++) diff --git a/src/lib_ccx/utility.h b/src/lib_ccx/utility.h index 11f138b26..a11e71329 100644 --- a/src/lib_ccx/utility.h +++ b/src/lib_ccx/utility.h @@ -26,6 +26,12 @@ struct ccx_rational extern int temp_debug; volatile extern sig_atomic_t change_filename_requested; +#ifndef DISABLE_RUST +extern int ccxr_verify_crc32(uint8_t *buf, int len); +extern int ccxr_levenshtein_dist(const uint64_t *s1, const uint64_t *s2, unsigned s1len, unsigned s2len); +extern int ccxr_levenshtein_dist_char(const char *s1, const char *s2, unsigned s1len, unsigned s2len); +#endif + int levenshtein_dist_char (const char *s1, const char *s2, unsigned s1len, unsigned s2len); void init_boundary_time (struct ccx_boundary_time *bt); void print_error (int mode, const char *fmt, ...); diff --git a/src/rust/lib_ccxr/src/util/bits.rs b/src/rust/lib_ccxr/src/util/bits.rs new file mode 100644 index 000000000..0127e6a0d --- /dev/null +++ b/src/rust/lib_ccxr/src/util/bits.rs @@ -0,0 +1,224 @@ +//! This module provides various bit-level operations, including parity calculation, +//! bit reversal, and hamming code decoding. +//! +//! - [`get_parity`]: Calculate the parity of an 8-bit value. +//! - [`get_reverse_byte`]: Reverse the bits in an 8-bit value. +//! - [`decode_hamming_8_4`]: Decode a Hamming(8,4) encoded byte. +//! - [`decode_hamming_24_18`]: Decode a Hamming(24,18) encoded value. +//! +//! # Conversion Guide +//! +//! | From | To | +//! |--------------------------------------------|--------------------------------| +//! | `PARITY_8` | [`get_parity`] | +//! | `REVERSE_8` | [`get_reverse_byte`] | +//! | `UNHAM_8_4` const or `unham_8_4` funcn | [`decode_hamming_8_4`] | +//! | `unham_24_18` | [`decode_hamming_24_18`] | +//! | `crc32_table` | [`get_crc32_byte`] | +//! | `verify_crc32` | [`verify_crc32`] | + +/// Equivalent to `PARITY_8[256]` const in `hamming.h` C code. +/// Instead use [`get_parity`] function to get parity bit based on your input. +const PARITY_TABLE: [bool; 256] = [ + false, true, true, false, true, false, false, true, true, false, false, true, false, true, + true, false, true, false, false, true, false, true, true, false, false, true, true, false, + true, false, false, true, true, false, false, true, false, true, true, false, false, true, + true, false, true, false, false, true, false, true, true, false, true, false, false, true, + true, false, false, true, false, true, true, false, true, false, false, true, false, true, + true, false, false, true, true, false, true, false, false, true, false, true, true, false, + true, false, false, true, true, false, false, true, false, true, true, false, false, true, + true, false, true, false, false, true, true, false, false, true, false, true, true, false, + true, false, false, true, false, true, true, false, false, true, true, false, true, false, + false, true, true, false, false, true, false, true, true, false, false, true, true, false, + true, false, false, true, false, true, true, false, true, false, false, true, true, false, + false, true, false, true, true, false, false, true, true, false, true, false, false, true, + true, false, false, true, false, true, true, false, true, false, false, true, false, true, + true, false, false, true, true, false, true, false, false, true, false, true, true, false, + true, false, false, true, true, false, false, true, false, true, true, false, true, false, + false, true, false, true, true, false, false, true, true, false, true, false, false, true, + true, false, false, true, false, true, true, false, false, true, true, false, true, false, + false, true, false, true, true, false, true, false, false, true, true, false, false, true, + false, true, true, false, +]; + +/// Equivalent to `REVERSE_8[256]` const in `hamming.h` C code +/// Instead use [`get_reverse_byte`] function to get any reversed bit based on your input. +const BIT_REVERSE_TABLE: [u8; 256] = [ + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, +]; + +/// Equivalent to `UNHAM_8_4[256]` const in `hamming.h` C code +/// Instead use [`decode_hamming_8_4`] function to get decoded hamming code. +const HAMMING_8_4_DECODER_TABLE: [u8; 256] = [ + 0x01, 0xff, 0x01, 0x01, 0xff, 0x00, 0x01, 0xff, 0xff, 0x02, 0x01, 0xff, 0x0a, 0xff, 0xff, 0x07, + 0xff, 0x00, 0x01, 0xff, 0x00, 0x00, 0xff, 0x00, 0x06, 0xff, 0xff, 0x0b, 0xff, 0x00, 0x03, 0xff, + 0xff, 0x0c, 0x01, 0xff, 0x04, 0xff, 0xff, 0x07, 0x06, 0xff, 0xff, 0x07, 0xff, 0x07, 0x07, 0x07, + 0x06, 0xff, 0xff, 0x05, 0xff, 0x00, 0x0d, 0xff, 0x06, 0x06, 0x06, 0xff, 0x06, 0xff, 0xff, 0x07, + 0xff, 0x02, 0x01, 0xff, 0x04, 0xff, 0xff, 0x09, 0x02, 0x02, 0xff, 0x02, 0xff, 0x02, 0x03, 0xff, + 0x08, 0xff, 0xff, 0x05, 0xff, 0x00, 0x03, 0xff, 0xff, 0x02, 0x03, 0xff, 0x03, 0xff, 0x03, 0x03, + 0x04, 0xff, 0xff, 0x05, 0x04, 0x04, 0x04, 0xff, 0xff, 0x02, 0x0f, 0xff, 0x04, 0xff, 0xff, 0x07, + 0xff, 0x05, 0x05, 0x05, 0x04, 0xff, 0xff, 0x05, 0x06, 0xff, 0xff, 0x05, 0xff, 0x0e, 0x03, 0xff, + 0xff, 0x0c, 0x01, 0xff, 0x0a, 0xff, 0xff, 0x09, 0x0a, 0xff, 0xff, 0x0b, 0x0a, 0x0a, 0x0a, 0xff, + 0x08, 0xff, 0xff, 0x0b, 0xff, 0x00, 0x0d, 0xff, 0xff, 0x0b, 0x0b, 0x0b, 0x0a, 0xff, 0xff, 0x0b, + 0x0c, 0x0c, 0xff, 0x0c, 0xff, 0x0c, 0x0d, 0xff, 0xff, 0x0c, 0x0f, 0xff, 0x0a, 0xff, 0xff, 0x07, + 0xff, 0x0c, 0x0d, 0xff, 0x0d, 0xff, 0x0d, 0x0d, 0x06, 0xff, 0xff, 0x0b, 0xff, 0x0e, 0x0d, 0xff, + 0x08, 0xff, 0xff, 0x09, 0xff, 0x09, 0x09, 0x09, 0xff, 0x02, 0x0f, 0xff, 0x0a, 0xff, 0xff, 0x09, + 0x08, 0x08, 0x08, 0xff, 0x08, 0xff, 0xff, 0x09, 0x08, 0xff, 0xff, 0x0b, 0xff, 0x0e, 0x03, 0xff, + 0xff, 0x0c, 0x0f, 0xff, 0x04, 0xff, 0xff, 0x09, 0x0f, 0xff, 0x0f, 0x0f, 0xff, 0x0e, 0x0f, 0xff, + 0x08, 0xff, 0xff, 0x05, 0xff, 0x0e, 0x0d, 0xff, 0xff, 0x0e, 0x0f, 0xff, 0x0e, 0x0e, 0xff, 0x0e, +]; + +/// Equivalent to `crc32_table[256]` const in `utility.c` C code +/// Instead use [`get_crc32_byte`] function to get CRC32 bit. +const CRC32_TABLE: [u32; 256] = [ + 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, + 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, + 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, + 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, + 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, + 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, + 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, + 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, + 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, + 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, + 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, + 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, + 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, + 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, + 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, + 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, + 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, + 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, + 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, + 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, + 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, + 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, + 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, + 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, + 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, + 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, + 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, + 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, + 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, + 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4, +]; + +/// Returns the parity of the given 8-bit unsigned integer. +/// +/// # Exmaples +/// ```rust +/// # use lib_ccxr::util::bits::*; +/// assert_eq!(get_parity(0), false); +/// assert_eq!(get_parity(1), true); +/// ``` +pub fn get_parity(value: u8) -> bool { + PARITY_TABLE[value as usize] +} + +/// Returns a byte with its bits flipped from given 8-bit unsigned integer. +/// +/// # Exmaples +/// ```rust +/// # use lib_ccxr::util::bits::*; +/// assert_eq!(get_reverse_byte(0), 0x00); +/// assert_eq!(get_reverse_byte(1), 0x80); +/// ``` +pub fn get_reverse_byte(value: u8) -> u8 { + BIT_REVERSE_TABLE[value as usize] +} + +/// Returns an Option of the decoded byte given a \[8,4\] hamming code byte. +/// (ETS 300 706, chapter 8.2) +/// +/// # Exmaples +/// ```rust +/// # use lib_ccxr::util::bits::*; +/// assert_eq!(decode_hamming_8_4(0x00), Some(0x01)); +/// assert_eq!(decode_hamming_8_4(0x01), None); +/// ``` +pub fn decode_hamming_8_4(value: u8) -> Option { + let decoded = HAMMING_8_4_DECODER_TABLE[value as usize]; + if decoded == 0xff { + None + } else { + Some(decoded & 0x0f) + } +} + +/// Returns an Option of the decoded byte given a \[24,18\] hamming code byte. +/// (ETS 300 706, chapter 8.3) +/// +/// # Exmaples +/// ```rust +/// # use lib_ccxr::util::bits::*; +/// assert_eq!(decode_hamming_24_18(0x00000000), Some(0x00000000)); +/// assert_eq!(decode_hamming_24_18(0x00000001), None); +/// ``` +pub fn decode_hamming_24_18(mut value: u32) -> Option { + let mut test: u8 = 0; + + // Tests A-F correspond to bits 0-6 respectively in 'test'. + for i in 0..23 { + test ^= (((value >> i) & 0x01) as u8) * (i + 33); + } + + // Only parity bit is tested for bit 24 + test ^= (((value >> 23) & 0x01) as u8) * 32u8; + + if (test & 0x1f) != 0x1f { + // Not all tests A-E correct + if (test & 0x20) == 0x20 { + // F correct: Double error + return None; + } + // Test F incorrect: Single error + value ^= 1 << (30 - test); + } + + Some( + (value & 0x000004) >> 2 + | (value & 0x000070) >> 3 + | (value & 0x007f00) >> 4 + | (value & 0x7f0000) >> 5, + ) +} + +/// Returns a crc 32-bit from given 8-bit unsigned integer. +/// +/// # Exmaples +/// ```rust +/// # use lib_ccxr::util::bits::*; +/// assert_eq!(get_crc32_byte(0), 0x00000000); +/// assert_eq!(get_crc32_byte(1), 0x04c11db7); +/// ``` +pub fn get_crc32_byte(value: u8) -> u32 { + CRC32_TABLE[value as usize] +} + +/// Verifies the CRC32-bit value +/// Rust equivalent for `verify_crc32` function in C. Uses Rust-native types as input and output. +pub fn verify_crc32(buf: &[u8]) -> bool { + let mut crc: i32 = -1; + for &byte in buf { + let expr = ((crc >> 24) ^ (byte & 0xff) as i32) & 0xff; + crc = (crc << 8) ^ get_crc32_byte(expr as u8) as i32; + } + crc == 0 +} diff --git a/src/rust/lib_ccxr/src/util/levenshtein.rs b/src/rust/lib_ccxr/src/util/levenshtein.rs new file mode 100644 index 000000000..3b23b6267 --- /dev/null +++ b/src/rust/lib_ccxr/src/util/levenshtein.rs @@ -0,0 +1,39 @@ +//! Provides function for calculating levenshtein distance. + +use std::cmp::min; + +/// Calculates the levenshtein distance between two slices. +/// +/// # Examples +/// ```rust +/// # use lib_ccxr::util::levenshtein::*; +/// assert_eq!(levenshtein(&[1,2,3,4,5], &[1,3,2,4,5,6]), 3); +/// ``` +pub fn levenshtein(a: &[T], b: &[T]) -> usize { + let mut column: Vec = (0..).take(a.len() + 1).collect(); + + for x in 1..=b.len() { + column[0] = x; + let mut lastdiag = x - 1; + for y in 1..=a.len() { + let olddiag = column[y]; + column[y] = min( + min(column[y] + 1, column[y - 1] + 1), + lastdiag + (if a[y - 1] == b[x - 1] { 0 } else { 1 }), + ); + lastdiag = olddiag; + } + } + + column[a.len()] +} + +/// Rust equivalent for `levenshtein_dist` function in C. Uses Rust-native types as input and output. +pub fn levenshtein_dist(s1: &[u64], s2: &[u64]) -> usize { + levenshtein(s1, s2) +} + +/// Rust equivalent for `levenshtein_dist_char` function in C. Uses Rust-native types as input and output. +pub fn levenshtein_dist_char(s1: &[T], s2: &[T]) -> usize { + levenshtein(s1, s2) +} diff --git a/src/rust/lib_ccxr/src/util/mod.rs b/src/rust/lib_ccxr/src/util/mod.rs index 504f17e26..01f9662df 100644 --- a/src/rust/lib_ccxr/src/util/mod.rs +++ b/src/rust/lib_ccxr/src/util/mod.rs @@ -1,3 +1,5 @@ //! Provides basic utilities used throughout the program. +pub mod bits; +pub mod levenshtein; pub mod log; diff --git a/src/rust/src/libccxr_exports/mod.rs b/src/rust/src/libccxr_exports/mod.rs index 60030671e..7180626f6 100644 --- a/src/rust/src/libccxr_exports/mod.rs +++ b/src/rust/src/libccxr_exports/mod.rs @@ -1,9 +1,12 @@ //! Provides C-FFI functions that are direct equivalent of functions available in C. use crate::ccx_s_options; -use core::panic; use lib_ccxr::util::log::*; +use lib_ccxr::util::{bits::*, levenshtein::*}; + +use core::panic; use std::convert::TryInto; +use std::os::raw::{c_char, c_int, c_uint}; /// Initializes the logger at the rust side. /// @@ -48,3 +51,62 @@ pub unsafe extern "C" fn ccxr_init_basic_logger(ccx_options: *const ccx_s_option )) .expect("Failed to initialize and setup the logger"); } + +/// Rust equivalent for `verify_crc32` function in C. Uses C-native types as input and output. +/// +/// # Safety +/// +/// `buf` should not be a NULL pointer and the length of buffer pointed by `buf` should be equal to +/// or less than `len`. +#[no_mangle] +pub unsafe extern "C" fn ccxr_verify_crc32(buf: *const u8, len: c_int) -> c_int { + let buf = std::slice::from_raw_parts(buf, len as usize); + if verify_crc32(buf) { + 1 + } else { + 0 + } +} + +/// Rust equivalent for `levenshtein_dist` function in C. Uses C-native types as input and output. +/// +/// # Safety +/// +/// `s1` and `s2` must valid slices of data with lengths of `s1len` and `s2len` respectively. +#[no_mangle] +pub unsafe extern "C" fn ccxr_levenshtein_dist( + s1: *const u64, + s2: *const u64, + s1len: c_uint, + s2len: c_uint, +) -> c_int { + let s1 = std::slice::from_raw_parts(s1, s1len.try_into().unwrap()); + let s2 = std::slice::from_raw_parts(s2, s2len.try_into().unwrap()); + + let ans = levenshtein_dist(s1, s2); + + ans.try_into() + .expect("Failed to convert the levenshtein distance to C int") +} + +/// Rust equivalent for `levenshtein_dist_char` function in C. Uses C-native types as input and output. +/// +/// # Safety +/// +/// `s1` and `s2` must valid slices of data and therefore not be null. They must have lengths +/// of `s1len` and `s2len` respectively. +#[no_mangle] +pub unsafe extern "C" fn ccxr_levenshtein_dist_char( + s1: *const c_char, + s2: *const c_char, + s1len: c_uint, + s2len: c_uint, +) -> c_int { + let s1 = std::slice::from_raw_parts(s1, s1len.try_into().unwrap()); + let s2 = std::slice::from_raw_parts(s2, s2len.try_into().unwrap()); + + let ans = levenshtein_dist_char(s1, s2); + + ans.try_into() + .expect("Failed to convert the levenshtein distance to C int") +} From 8d9bf42be26c4467f761d3cd8e44674258bfb52d Mon Sep 17 00:00:00 2001 From: Ishan Grover <123376573+IshanGrover2004@users.noreply.github.com> Date: Wed, 17 Jul 2024 03:34:48 +0530 Subject: [PATCH 25/27] [FEAT] Add time units module in `lib_ccxr` (#1623) * chore: Add cargo dependencies * feat: Make time module in `lib_ccxr` * feat: Add conversion guide in `time/mod.rs` module & Create `units` module * feat: Add time units code * feat: Make time module in `lib_ccxr/util` & Add helper function * feat: Add utils time related functions * feat: Add extern functions in `libccxr_exports` * feat: Add extern functions in C and use in proper place * docs: Mention in Changelogs --- docs/CHANGES.TXT | 3 +- src/lib_ccx/ccx_common_common.c | 3 + src/lib_ccx/ccx_common_common.h | 5 + src/lib_ccx/utility.c | 15 + src/lib_ccx/utility.h | 4 + src/rust/Cargo.lock | 308 ++++++++----- src/rust/lib_ccxr/Cargo.lock | 170 +++++++ src/rust/lib_ccxr/Cargo.toml | 11 +- src/rust/lib_ccxr/src/lib.rs | 1 + src/rust/lib_ccxr/src/time/mod.rs | 23 + src/rust/lib_ccxr/src/time/units.rs | 645 +++++++++++++++++++++++++++ src/rust/lib_ccxr/src/util/mod.rs | 14 + src/rust/lib_ccxr/src/util/time.rs | 35 ++ src/rust/src/libccxr_exports/mod.rs | 2 + src/rust/src/libccxr_exports/time.rs | 125 ++++++ 15 files changed, 1249 insertions(+), 115 deletions(-) create mode 100644 src/rust/lib_ccxr/src/time/mod.rs create mode 100644 src/rust/lib_ccxr/src/time/units.rs create mode 100644 src/rust/lib_ccxr/src/util/time.rs create mode 100644 src/rust/src/libccxr_exports/time.rs diff --git a/docs/CHANGES.TXT b/docs/CHANGES.TXT index 9897aae4e..a722bfbe0 100644 --- a/docs/CHANGES.TXT +++ b/docs/CHANGES.TXT @@ -1,7 +1,8 @@ 0.95 (to be released) ----------------- +- New: Add time units module in lib_ccxr (#1623) - New: Add bits and levenshtein module in lib_ccxr (#1627) -- New: [FEAT] Add constants module in lib_ccxr (#1624) +- New: Add constants module in lib_ccxr (#1624) - New: Add log module in lib_ccxr (#1622) - New: Create `lib_ccxr` and `libccxr_exports` (#1621) - Fix: Unexpected behavior of get_write_interval (#1609) diff --git a/src/lib_ccx/ccx_common_common.c b/src/lib_ccx/ccx_common_common.c index 91a765283..f150da7d2 100644 --- a/src/lib_ccx/ccx_common_common.c +++ b/src/lib_ccx/ccx_common_common.c @@ -26,6 +26,9 @@ int fdprintf(int fd, const char *fmt, ...) void millis_to_time(LLONG milli, unsigned *hours, unsigned *minutes, unsigned *seconds, unsigned *ms) { +#ifndef DISABLE_RUST + return ccxr_millis_to_time(milli, hours, minutes, seconds, ms); +#endif /* ifndef DISABLE_RUST */ // LLONG milli = (LLONG) ((ccblock*1000)/29.97); *ms = (unsigned)(milli % 1000); // milliseconds milli = (milli - *ms) / 1000; // Remainder, in seconds diff --git a/src/lib_ccx/ccx_common_common.h b/src/lib_ccx/ccx_common_common.h index b26c6965a..d9f6c3218 100644 --- a/src/lib_ccx/ccx_common_common.h +++ b/src/lib_ccx/ccx_common_common.h @@ -43,6 +43,11 @@ int cc608_parity(unsigned int byte); int fdprintf(int fd, const char *fmt, ...); void millis_to_time(LLONG milli, unsigned *hours, unsigned *minutes,unsigned *seconds, unsigned *ms); + +#ifndef DISABLE_RUST +extern void ccxr_millis_to_time(LLONG milli, unsigned *hours, unsigned *minutes,unsigned *seconds, unsigned *ms); +#endif // !DISABLE_RUST + void freep(void *arg); void dbg_print(LLONG mask, const char *fmt, ...); unsigned char *debug_608_to_ASC(unsigned char *ccdata, int channel); diff --git a/src/lib_ccx/utility.c b/src/lib_ccx/utility.c index 2be551f5c..b1a0c22af 100644 --- a/src/lib_ccx/utility.c +++ b/src/lib_ccx/utility.c @@ -89,6 +89,9 @@ int verify_crc32(uint8_t *buf, int len) int stringztoms(const char *s, struct ccx_boundary_time *bt) { +#ifndef DISABLE_RUST + return ccxr_stringztoms(s, bt); +#endif unsigned ss = 0, mm = 0, hh = 0; int value = -1; int colons = 0; @@ -133,6 +136,10 @@ int stringztoms(const char *s, struct ccx_boundary_time *bt) } void timestamp_to_srttime(uint64_t timestamp, char *buffer) { +#ifndef DISABLE_RUST + return ccxr_timestamp_to_srttime(timestamp, buffer); +#endif + uint64_t p = timestamp; uint8_t h = (uint8_t)(p / 3600000); uint8_t m = (uint8_t)(p / 60000 - 60 * h); @@ -142,6 +149,10 @@ void timestamp_to_srttime(uint64_t timestamp, char *buffer) } void timestamp_to_vtttime(uint64_t timestamp, char *buffer) { +#ifndef DISABLE_RUST + return ccxr_timestamp_to_vtttime(timestamp, buffer); +#endif + uint64_t p = timestamp; uint8_t h = (uint8_t)(p / 3600000); uint8_t m = (uint8_t)(p / 60000 - 60 * h); @@ -202,6 +213,10 @@ int levenshtein_dist_char(const char *s1, const char *s2, unsigned s1len, unsign void millis_to_date(uint64_t timestamp, char *buffer, enum ccx_output_date_format date_format, char millis_separator) { +#ifndef DISABLE_RUST + return ccxr_millis_to_date(timestamp, buffer, date_format, millis_separator); +#endif + time_t secs; unsigned int millis; char c_temp[80]; diff --git a/src/lib_ccx/utility.h b/src/lib_ccx/utility.h index a11e71329..6fc6eafa1 100644 --- a/src/lib_ccx/utility.h +++ b/src/lib_ccx/utility.h @@ -30,6 +30,10 @@ volatile extern sig_atomic_t change_filename_requested; extern int ccxr_verify_crc32(uint8_t *buf, int len); extern int ccxr_levenshtein_dist(const uint64_t *s1, const uint64_t *s2, unsigned s1len, unsigned s2len); extern int ccxr_levenshtein_dist_char(const char *s1, const char *s2, unsigned s1len, unsigned s2len); +extern void ccxr_timestamp_to_srttime(uint64_t timestamp, char *buffer); +extern void ccxr_timestamp_to_vtttime(uint64_t timestamp, char *buffer); +extern void ccxr_millis_to_date(uint64_t timestamp, char *buffer, enum ccx_output_date_format date_format, char millis_separator); +extern int ccxr_stringztoms(const char *s, struct ccx_boundary_time *bt); #endif int levenshtein_dist_char (const char *s1, const char *s2, unsigned s1len, unsigned s2len); diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index ce5c11dc3..309e944bd 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "aho-corasick" -version = "1.0.5" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c378d78423fdad8089616f827526ee33c19f2fddbd5de1629152c9593ba4783" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -33,9 +33,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "bindgen" @@ -78,7 +78,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.52", + "syn 2.0.71", "which", ] @@ -96,18 +96,9 @@ checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "camino" -version = "1.1.6" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" - -[[package]] -name = "cc" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] +checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" [[package]] name = "ccx_rust" @@ -141,15 +132,43 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clang-sys" -version = "1.6.1" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", "libloading", ] +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derive_more" +version = "0.99.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.71", +] + [[package]] name = "dyn_buf" version = "0.1.0" @@ -158,9 +177,9 @@ checksum = "74c57ab96715773d9cb9789b38eb7cbf04b3c6f5624a9d98f51761603376767c" [[package]] name = "either" -version = "1.9.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "env_logger" @@ -177,25 +196,14 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.3" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ - "errno-dragonfly", "libc", "windows-sys", ] -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] - [[package]] name = "find-crate" version = "0.6.3" @@ -222,9 +230,9 @@ dependencies = [ [[package]] name = "home" -version = "0.5.5" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" dependencies = [ "windows-sys", ] @@ -254,11 +262,17 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "lazycell" @@ -268,9 +282,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "leptonica-sys" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eff3f1dc2f0112411228f8db99ca8a6a1157537a7887b28b1c91fdc4051fb326" +checksum = "1c924779fadc73838b9390ddda5fc1939f844fb43bd44ef6794c32bd6e52238a" dependencies = [ "bindgen 0.64.0", "pkg-config", @@ -282,41 +296,44 @@ name = "lib_ccxr" version = "0.1.0" dependencies = [ "bitflags 2.6.0", + "derive_more", + "thiserror", + "time", ] [[package]] name = "libc" -version = "0.2.147" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libloading" -version = "0.7.4" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d" dependencies = [ "cfg-if", - "winapi", + "windows-targets", ] [[package]] name = "linux-raw-sys" -version = "0.4.7" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "log" -version = "0.4.20" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "memchr" -version = "2.6.3" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "minimal-lexical" @@ -334,20 +351,26 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "palette" @@ -375,9 +398,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "peeking_take_while" @@ -415,7 +438,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.71", ] [[package]] @@ -429,34 +452,40 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.27" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "prettyplease" -version = "0.2.16" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" +checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" dependencies = [ "proc-macro2", - "syn 2.0.52", + "syn 2.0.71", ] [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -478,9 +507,9 @@ checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" [[package]] name = "regex" -version = "1.9.5" +version = "1.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" dependencies = [ "aho-corasick", "memchr", @@ -490,9 +519,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.8" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", @@ -501,9 +530,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.5" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "rsmpeg" @@ -523,11 +552,20 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + [[package]] name = "rustix" -version = "0.38.13" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7db8590df6dfcd144d22afd1b83b36c21a18d7cbc1dc4bb5295a8712e9eb662" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ "bitflags 2.6.0", "errno", @@ -550,31 +588,37 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + [[package]] name = "serde" -version = "1.0.188" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.188" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.71", ] [[package]] name = "shlex" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "siphasher" @@ -595,9 +639,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.52" +version = "2.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462" dependencies = [ "proc-macro2", "quote", @@ -606,9 +650,9 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.2.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] @@ -627,22 +671,53 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.48" +version = "1.0.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7" +checksum = "f2675633b1499176c2dff06b0856a27976a8f9d436737b4cf4f312d4d91d8bbb" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.48" +version = "1.0.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" +checksum = "d20468752b09f49e909e55a5d338caa8bedf615594e9d80bc4c565d30faf798c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.71", +] + +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", ] [[package]] @@ -656,9 +731,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "vcpkg" @@ -696,11 +771,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ - "winapi", + "windows-sys", ] [[package]] @@ -711,22 +786,23 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" -version = "0.48.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", + "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", @@ -735,42 +811,48 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.48.5" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.48.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/src/rust/lib_ccxr/Cargo.lock b/src/rust/lib_ccxr/Cargo.lock index 79aa1872e..aecb788a5 100644 --- a/src/rust/lib_ccxr/Cargo.lock +++ b/src/rust/lib_ccxr/Cargo.lock @@ -8,9 +8,179 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derive_more" +version = "0.99.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + [[package]] name = "lib_ccxr" version = "0.1.0" dependencies = [ "bitflags", + "derive_more", + "thiserror", + "time", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "serde" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +dependencies = [ + "serde_derive", ] + +[[package]] +name = "serde_derive" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "2.0.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2675633b1499176c2dff06b0856a27976a8f9d436737b4cf4f312d4d91d8bbb" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d20468752b09f49e909e55a5d338caa8bedf615594e9d80bc4c565d30faf798c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" diff --git a/src/rust/lib_ccxr/Cargo.toml b/src/rust/lib_ccxr/Cargo.toml index 7a8ff30e3..8bd21e57b 100644 --- a/src/rust/lib_ccxr/Cargo.toml +++ b/src/rust/lib_ccxr/Cargo.toml @@ -7,9 +7,18 @@ edition = "2021" [dependencies] bitflags = "2.6.0" +thiserror = "1.0.61" +time = { version = "0.3.36", features = ["macros", "formatting"] } +derive_more = "0.99.18" [features] -default = ["enable_sharing", "wtv_debug", "enable_ffmpeg", "debug", "with_libcurl"] +default = [ + "enable_sharing", + "wtv_debug", + "enable_ffmpeg", + "debug", + "with_libcurl", +] enable_sharing = [] wtv_debug = [] enable_ffmpeg = [] diff --git a/src/rust/lib_ccxr/src/lib.rs b/src/rust/lib_ccxr/src/lib.rs index 45ee8e79c..c1172cf5c 100644 --- a/src/rust/lib_ccxr/src/lib.rs +++ b/src/rust/lib_ccxr/src/lib.rs @@ -1,2 +1,3 @@ pub mod common; +pub mod time; pub mod util; diff --git a/src/rust/lib_ccxr/src/time/mod.rs b/src/rust/lib_ccxr/src/time/mod.rs new file mode 100644 index 000000000..9cd41dac1 --- /dev/null +++ b/src/rust/lib_ccxr/src/time/mod.rs @@ -0,0 +1,23 @@ +//! Provide types for storing time in different formats +//! +//! Time can be represented in one of following formats: +//! - [`Timestamp`] as number of milliseconds +//! - [`MpegClockTick`] as number of clock ticks (as defined in the MPEG standard) +//! - [`FrameCount`] as number of frames +//! - [`GopTimeCode`] as a GOP time code (as defined in the MPEG standard) +//! +//! # Conversion Guide +//! +//! | From | To | +//! |-------------------------------------------|-------------------------------------------------------| +//! | `ccx_boundary_time` | [`Option`](Timestamp) | +//! | any fts | [`Timestamp`] | +//! | `ccx_output_date_format` | [`TimestampFormat`] | +//! | any pts | [`MpegClockTick`] | +//! | any frame count | [`FrameCount`] | +//! | `gop_time_code` | [`GopTimeCode`] | +//! | `print_mstime_static` | [`Timestamp::to_hms_millis_time`] | +//! | `gop_accepted` | [`GopTimeCode::did_rollover`] + some additional logic | +//! | `calculate_ms_gop_time` | [`GopTimeCode::new`], [`GopTimeCode::timestamp`] | + +pub mod units; diff --git a/src/rust/lib_ccxr/src/time/units.rs b/src/rust/lib_ccxr/src/time/units.rs new file mode 100644 index 000000000..611806722 --- /dev/null +++ b/src/rust/lib_ccxr/src/time/units.rs @@ -0,0 +1,645 @@ +use std::convert::TryInto; +use std::fmt::Write; +use std::num::TryFromIntError; +use std::os::raw::c_int; +use std::time::{SystemTime, UNIX_EPOCH}; + +use derive_more::{Add, Neg, Sub}; +use thiserror::Error; +use time::{ + error::Format, + macros::{datetime, format_description}, + Duration, +}; + +extern "C" { + static mut MPEG_CLOCK_FREQ: c_int; +} + +/// Represents a timestamp in milliseconds. +/// +/// The number can be negetive. +#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Add, Sub, Neg)] +pub struct Timestamp { + millis: i64, +} + +/// Represents an error during operations on [`Timestamp`]. +#[derive(Error, Debug)] +pub enum TimestampError { + #[error("input parameter given is out of range")] + InputOutOfRangeError, + #[error("timestamp is out of range")] + OutOfRangeError(#[from] TryFromIntError), + #[error("error ocurred during formatting")] + FormattingError(#[from] std::fmt::Error), + #[error("error ocurred during formatting a date")] + DateFormattingError(#[from] Format), + #[error("error ocurred during parsing")] + ParsingError, +} + +/// Represents the different string formats for [`Timestamp`]. +pub enum TimestampFormat { + /// Format: blank string. + /// + /// # Examples + /// ```rust + /// # use crate::time::units::{Timestamp, TimestampFormat}; + /// let timestamp = Timestamp::from_millis(6524365); + /// let output = timestamp.to_formatted_time(TimestampFormat::None).unwrap(); + /// assert_eq!(output, ""); + /// ``` + None, + + /// Format: `{hour:02}:{minute:02}:{second:02}`. + /// + /// # Examples + /// ```rust + /// # use crate::time::units::{Timestamp, TimestampFormat}; + /// let timestamp = Timestamp::from_millis(6524365); + /// let output = timestamp.to_formatted_time(TimestampFormat::HHMMSS).unwrap(); + /// assert_eq!(output, "01:48:44"); + /// ``` + HHMMSS, + + /// Format: `{second:02}{millis_separator}{millis:03}`. + /// + /// # Examples + /// ```rust + /// # use crate::time::units::{Timestamp, TimestampFormat}; + /// let timestamp = Timestamp::from_millis(6524365); + /// let output = timestamp.to_formatted_time( + /// TimestampFormat::Seconds { + /// millis_separator: ',', + /// }, + /// ).unwrap(); + /// assert_eq!(output, "6524,365"); + /// ``` + Seconds { millis_separator: char }, + + /// Format: + /// `{year:04}{month:02}{day:02}{hour:02}{minute:02}{second:02}{millis_separator}{millis:03}`. + /// + /// # Examples + /// ```rust + /// # use crate::time::units::{Timestamp, TimestampFormat}; + /// // 11 March 2023 14:53:36.749 in UNIX timestamp. + /// let timestamp = Timestamp::from_millis(1678546416749); + /// let output = timestamp.to_formatted_time( + /// TimestampFormat::Date { + /// millis_separator: ',', + /// }, + /// ).unwrap(); + /// assert_eq!(output, "20230311145336,749"); + /// ``` + Date { millis_separator: char }, + + /// Format: `{hour:02}:{minute:02}:{second:02},{millis:03}`. + /// + /// # Examples + /// ```rust + /// # use lib_ccxr::util::time::{Timestamp, TimestampFormat}; + /// let timestamp = Timestamp::from_millis(6524365); + /// let output = timestamp.to_formatted_time(TimestampFormat::HHMMSSFFF).unwrap(); + /// assert_eq!(output, "01:48:44,365"); + /// ``` + HHMMSSFFF, +} + +impl Timestamp { + /// Create a new [`Timestamp`] based on the number of milliseconds since the Unix Epoch. + pub fn now() -> Timestamp { + let duration = SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("System Time cannot be behind the Unix Epoch"); + + Timestamp { + millis: duration.as_millis() as i64, + } + } + + /// Create a new [`Timestamp`] from number of milliseconds. + pub const fn from_millis(millis: i64) -> Timestamp { + Timestamp { millis } + } + + /// Create a new [`Timestamp`] from hours, minutes, seconds and milliseconds. + /// + /// It will fail if any parameter doesn't follow their respective ranges: + /// + /// | Parameter | Range | + /// |-----------|---------| + /// | minutes | 0 - 59 | + /// | seconds | 0 - 59 | + /// | millis | 0 - 999 | + pub fn from_hms_millis( + hours: u8, + minutes: u8, + seconds: u8, + millis: u16, + ) -> Result { + if minutes < 60 && seconds < 60 && millis < 1000 { + Ok(Timestamp::from_millis( + (hours as i64) * 3_600_000 + + (minutes as i64) * 60_000 + + (seconds as i64) * 1000 + + millis as i64, + )) + } else { + Err(TimestampError::InputOutOfRangeError) + } + } + + /// Returns the number of milliseconds. + /// + /// # Examples + /// ```rust + /// # use lib_ccxr::util::time::Timestamp; + /// let timestamp = Timestamp::from_millis(6524365); + /// assert_eq!(timestamp.millis(), 6524365); + /// ``` + pub fn millis(&self) -> i64 { + self.millis + } + + /// Returns the number of whole seconds. + /// + /// # Examples + /// ```rust + /// # use lib_ccxr::util::time::Timestamp; + /// let timestamp = Timestamp::from_millis(6524365); + /// assert_eq!(timestamp.seconds(), 6524); + /// ``` + pub fn seconds(&self) -> i64 { + self.millis / 1000 + } + + /// Returns the number of whole seconds and leftover milliseconds as unsigned integers. + /// + /// It will return an [`TimestampError::OutOfRangeError`] if the timestamp is negetive. + /// + /// # Examples + /// ```rust + /// # use lib_ccxr::util::time::Timestamp; + /// let timestamp = Timestamp::from_millis(6524365); + /// assert_eq!(timestamp.as_sec_millis().unwrap(), (6524, 365)); + /// ``` + pub fn as_sec_millis(&self) -> Result<(u64, u16), TimestampError> { + let millis: u64 = self.millis.try_into()?; + let s = millis / 1000; + let u = millis % 1000; + Ok((s, u as u16)) + } + + /// Returns the time in the form of hours, minutes, seconds and milliseconds as unsigned + /// integers. + /// + /// It will return an [`TimestampError::OutOfRangeError`] if the timestamp is negetive. + /// + /// # Examples + /// ```rust + /// # use lib_ccxr::util::time::Timestamp; + /// let timestamp = Timestamp::from_millis(6524365); + /// assert_eq!(timestamp.as_hms_millis().unwrap(), (1, 48, 44, 365)); + /// ``` + /// ```rust + /// # use lib_ccxr::util::time::{Timestamp, TimestampError}; + /// let timestamp = Timestamp::from_millis(1678546416749); + /// assert!(matches!( + /// timestamp.as_hms_millis().unwrap_err(), + /// TimestampError::OutOfRangeError(_) + /// )); + /// ``` + pub fn as_hms_millis(&self) -> Result<(u8, u8, u8, u16), TimestampError> { + let millis: u64 = self.millis.try_into()?; + let h = millis / 3600000; + let m = millis / 60000 - 60 * h; + let s = millis / 1000 - 3600 * h - 60 * m; + let u = millis - 3600000 * h - 60000 * m - 1000 * s; + if h > 24 { + println!("{}", h) + } + Ok((h.try_into()?, m as u8, s as u8, u as u16)) + } + + /// Fills `output` with the [`Timestamp`] using SRT's timestamp format. + /// + /// # Examples + /// ```rust + /// # use lib_ccxr::util::time::Timestamp; + /// let timestamp = Timestamp::from_millis(6524365); + /// let mut output = String::new(); + /// timestamp.write_srt_time(&mut output); + /// assert_eq!(output, "01:48:44,365"); + /// ``` + pub fn write_srt_time(&self, output: &mut String) -> Result<(), TimestampError> { + let (h, m, s, u) = self.as_hms_millis()?; + write!(output, "{:02}:{:02}:{:02},{:03}", h, m, s, u)?; + Ok(()) + } + + /// Fills `output` with the [`Timestamp`] using VTT's timestamp format. + /// + /// # Examples + /// ```rust + /// # use lib_ccxr::util::time::Timestamp; + /// let timestamp = Timestamp::from_millis(6524365); + /// let mut output = String::new(); + /// timestamp.write_vtt_time(&mut output); + /// assert_eq!(output, "01:48:44.365"); + /// ``` + pub fn write_vtt_time(&self, output: &mut String) -> Result<(), TimestampError> { + let (h, m, s, u) = self.as_hms_millis()?; + write!(output, "{:02}:{:02}:{:02}.{:03}", h, m, s, u)?; + Ok(()) + } + + /// Fills `output` with the [`Timestamp`] using + /// "{sign}{hour:02}:{minute:02}:{second:02}{sep}{millis:03}" format, where `sign` can be `-` + /// if time is negetive or blank if it is positive. + /// + /// # Examples + /// ```rust + /// # use lib_ccxr::util::time::Timestamp; + /// let timestamp = Timestamp::from_millis(6524365); + /// let mut output = String::new(); + /// timestamp.write_hms_millis_time(&mut output, ':'); + /// assert_eq!(output, "01:48:44:365"); + /// ``` + pub fn write_hms_millis_time( + &self, + output: &mut String, + sep: char, + ) -> Result<(), TimestampError> { + let sign = if self.millis < 0 { "-" } else { "" }; + let timestamp = if self.millis < 0 { -*self } else { *self }; + let (h, m, s, u) = timestamp.as_hms_millis()?; + write!(output, "{}{:02}:{:02}:{:02}{}{:03}", sign, h, m, s, sep, u)?; + Ok(()) + } + + /// Fills `output` with the [`Timestamp`] using ctime's format. + /// + /// # Examples + /// ```rust + /// # use lib_ccxr::util::time::Timestamp; + /// let timestamp = Timestamp::from_millis(6524365); + /// let mut output = String::new(); + /// timestamp.write_ctime(&mut output); + /// assert_eq!(output, "Thu Jan 01 01:48:44 1970"); + /// ``` + pub fn write_ctime(&self, output: &mut String) -> Result<(), TimestampError> { + let (sec, millis) = self.as_sec_millis()?; + let d = datetime!(1970-01-01 0:00) + + Duration::new(sec.try_into()?, (millis as i32) * 1_000_000); + let format = format_description!( + "[weekday repr:short] [month repr:short] [day] [hour]:[minute]:[second] [year]" + ); + write!(output, "{}", d.format(&format)?)?; + Ok(()) + } + + /// Fills `output` with the [`Timestamp`] using format specified by [`TimestampFormat`]. + /// + /// See [`TimestampFormat`] for examples. + pub fn write_formatted_time( + &self, + output: &mut String, + format: TimestampFormat, + ) -> Result<(), TimestampError> { + match format { + TimestampFormat::None => Ok(()), + TimestampFormat::HHMMSS => { + let (h, m, s, _) = self.as_hms_millis()?; + write!(output, "{:02}:{:02}:{:02}", h, m, s)?; + Ok(()) + } + TimestampFormat::Seconds { millis_separator } => { + let (sec, millis) = self.as_sec_millis()?; + write!(output, "{}{}{:03}", sec, millis_separator, millis)?; + Ok(()) + } + TimestampFormat::Date { millis_separator } => { + let (sec, millis) = self.as_sec_millis()?; + let d = datetime!(1970-01-01 0:00) + + Duration::new(sec.try_into()?, (millis as i32) * 1_000_000); + let format1 = format_description!("[year][month][day][hour][minute][second]"); + let format2 = format_description!("[subsecond digits:3]"); + + write!( + output, + "{}{}{}", + d.format(&format1)?, + millis_separator, + d.format(&format2)? + )?; + Ok(()) + } + TimestampFormat::HHMMSSFFF => self.write_srt_time(output), + } + } + + /// Returns a formatted [`Timestamp`] using SRT's timestamp format. + /// + /// # Examples + /// ```rust + /// # use lib_ccxr::util::time::Timestamp; + /// let timestamp = Timestamp::from_millis(6524365); + /// assert_eq!(timestamp.to_srt_time().unwrap(), "01:48:44,365"); + /// ``` + pub fn to_srt_time(&self) -> Result { + let mut s = String::new(); + self.write_srt_time(&mut s)?; + Ok(s) + } + + /// Returns a formatted [`Timestamp`] using VTT's timestamp format. + /// + /// # Examples + /// ```rust + /// # use lib_ccxr::util::time::Timestamp; + /// let timestamp = Timestamp::from_millis(6524365); + /// assert_eq!(timestamp.to_vtt_time().unwrap(), "01:48:44.365"); + /// ``` + pub fn to_vtt_time(&self) -> Result { + let mut s = String::new(); + self.write_vtt_time(&mut s)?; + Ok(s) + } + + /// Returns a formatted [`Timestamp`] using + /// "{sign}{hour:02}:{minute:02}:{second:02}{sep}{millis:03}" format, where `sign` can be `-` + /// if time is negetive or blank if it is positive. + /// + /// # Examples + /// ```rust + /// # use lib_ccxr::util::time::Timestamp; + /// let timestamp = Timestamp::from_millis(6524365); + /// assert_eq!(timestamp.to_hms_millis_time(':').unwrap(), "01:48:44:365"); + /// ``` + pub fn to_hms_millis_time(&self, sep: char) -> Result { + let mut s = String::new(); + self.write_hms_millis_time(&mut s, sep)?; + Ok(s) + } + + /// Returns a formatted [`Timestamp`] using ctime's format. + /// + /// # Examples + /// ```rust + /// # use lib_ccxr::util::time::Timestamp; + /// let timestamp = Timestamp::from_millis(6524365); + /// assert_eq!(timestamp.to_ctime().unwrap(), "Thu Jan 01 01:48:44 1970"); + /// ``` + pub fn to_ctime(&self) -> Result { + let mut s = String::new(); + self.write_ctime(&mut s)?; + Ok(s) + } + + /// Returns a formatted [`Timestamp`] using format specified by [`TimestampFormat`]. + /// + /// See [`TimestampFormat`] for examples. + pub fn to_formatted_time(&self, format: TimestampFormat) -> Result { + let mut s = String::new(); + self.write_formatted_time(&mut s, format)?; + Ok(s) + } + + /// Creates a [`Timestamp`] by parsing `input` using format `SS` or `MM:SS` or `HH:MM:SS`. + /// + /// # Examples + /// ```rust + /// # use lib_ccxr::util::time::Timestamp; + /// let timestamp = Timestamp::parse_optional_hhmmss_from_str("01:12:45").unwrap(); + /// assert_eq!(timestamp, Timestamp::from_millis(4_365_000)); + /// ``` + pub fn parse_optional_hhmmss_from_str(input: &str) -> Result { + let mut numbers = input + .split(':') + .map(|x| x.parse::().map_err(|_| TimestampError::ParsingError)) + .rev(); + + let mut millis: u64 = 0; + + let seconds: u64 = numbers.next().ok_or(TimestampError::ParsingError)??.into(); + if seconds > 59 { + return Err(TimestampError::InputOutOfRangeError); + } + millis += seconds * 1000; + + if let Some(x) = numbers.next() { + let minutes: u64 = x?.into(); + if minutes > 59 { + return Err(TimestampError::InputOutOfRangeError); + } + millis += 60_000 * minutes; + } + + if let Some(x) = numbers.next() { + let hours: u64 = x?.into(); + millis += 3_600_000 * hours; + } + + if numbers.next().is_some() { + return Err(TimestampError::ParsingError); + } + + Ok(Timestamp::from_millis(millis.try_into()?)) + } +} + +/// Represent the number of clock ticks as defined in Mpeg standard. +/// +/// This number can never be negetive. +#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Add, Sub)] +pub struct MpegClockTick(i64); + +impl MpegClockTick { + /// Returns the ratio to convert a clock tick to time duration. + pub fn mpeg_clock_freq() -> i64 { + unsafe { MPEG_CLOCK_FREQ.into() } + } + + /// Create a value representing `ticks` clock ticks. + pub fn new(ticks: i64) -> MpegClockTick { + MpegClockTick(ticks) + } + + /// Returns the number of clock ticks. + pub fn as_i64(&self) -> i64 { + self.0 + } + + /// Converts the clock ticks to its equivalent time duration. + /// + /// The conversion ratio used is [`MpegClockTick::MPEG_CLOCK_FREQ`]. + pub fn as_timestamp(&self) -> Timestamp { + Timestamp::from_millis(self.0 / (MpegClockTick::mpeg_clock_freq() / 1000)) + } +} + +/// Represents the number of frames. +/// +/// This number can never be negetive. +#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Add, Sub)] +pub struct FrameCount(u64); + +impl FrameCount { + /// Create a value representing `frames` number of frames. + pub const fn new(frames: u64) -> FrameCount { + FrameCount(frames) + } + + /// Returns the number of frames. + pub fn as_u64(&self) -> u64 { + self.0 + } + + /// Converts the frames to its equivalent time duration. + /// + /// The conversion ratio used is `fps`. + pub fn as_timestamp(&self, fps: f64) -> Timestamp { + Timestamp::from_millis((self.0 as f64 * 1000.0 / fps) as i64) + } + + /// Converts the frames to its equivalent number of clock ticks. + /// + /// The conversion ratio used is [`MpegClockTick::MPEG_CLOCK_FREQ`] and `fps`. + pub fn as_mpeg_clock_tick(&self, fps: f64) -> MpegClockTick { + MpegClockTick::new(((self.0 * MpegClockTick::mpeg_clock_freq() as u64) as f64 / fps) as i64) + } +} + +/// Represents a GOP Time code as defined in the Mpeg standard. +/// +/// This structure stores its time in the form of hours, minutes, seconds and pictures. This +/// structure also stores its time in the form of a [`Timestamp`] when it is created. This +/// [`Timestamp`] can be modified by [`timestamp_mut`](GopTimeCode::timestamp_mut) and an +/// additional 24 hours may be added on rollover, so it is not necessary that the above two +/// formats refer to the same time. Therefore it is recommended to only rely on the +/// [`Timestamp`] instead of the other format. +#[derive(Copy, Clone, Debug)] +pub struct GopTimeCode { + drop_frame: bool, + time_code_hours: u8, + time_code_minutes: u8, + time_code_seconds: u8, + time_code_pictures: u8, + timestamp: Timestamp, +} + +impl GopTimeCode { + /// Create a new [`GopTimeCode`] from the specified parameters. + /// + /// The number of frames or pictures is converted to time duration using `fps`. + /// + /// If `rollover` is true, then an extra of 24 hours will added. + /// + /// It will return [`None`] if any parameter doesn't follow their respective ranges: + /// + /// | Parameter | Range | + /// |-----------|--------| + /// | hours | 0 - 23 | + /// | minutes | 0 - 59 | + /// | seconds | 0 - 59 | + /// | pictures | 0 - 59 | + pub fn new( + drop_frame: bool, + hours: u8, + minutes: u8, + seconds: u8, + pictures: u8, + fps: f64, + rollover: bool, + ) -> Option { + if hours < 24 && minutes < 60 && seconds < 60 && pictures < 60 { + let millis = (1000.0 * (pictures as f64) / fps) as u16; + let extra_hours = if rollover { 24 } else { 0 }; + let timestamp = + Timestamp::from_hms_millis(hours + extra_hours, minutes, seconds, millis) + .expect("The fps given is probably too low"); + + Some(GopTimeCode { + drop_frame, + time_code_hours: hours, + time_code_minutes: minutes, + time_code_seconds: seconds, + time_code_pictures: pictures, + timestamp, + }) + } else { + None + } + } + + /// Returns the GOP time code in its equivalent time duration. + pub fn timestamp(&self) -> Timestamp { + self.timestamp + } + + /// Returns a mutable reference to internal [`Timestamp`]. + pub fn timestamp_mut(&mut self) -> &mut Timestamp { + &mut self.timestamp + } + + /// Check if a rollover has ocurred by comparing the previous [`GopTimeCode`] that is `prev` + /// with the current [`GopTimeCode`]. + pub fn did_rollover(&self, prev: &GopTimeCode) -> bool { + prev.time_code_hours == 23 + && prev.time_code_minutes == 59 + && self.time_code_hours == 0 + && self.time_code_minutes == 0 + } + + /// Constructs a [`GopTimeCode`] from its individual fields. + /// + /// # Safety + /// + /// The fields other than [`Timestamp`] may not be accurate if it is changed using + /// [`timestamp_mut`](GopTimeCode::timestamp_mut). + pub unsafe fn from_raw_parts( + drop_frame: bool, + hours: u8, + minutes: u8, + seconds: u8, + pictures: u8, + timestamp: Timestamp, + ) -> GopTimeCode { + GopTimeCode { + drop_frame, + time_code_hours: hours, + time_code_minutes: minutes, + time_code_seconds: seconds, + time_code_pictures: pictures, + timestamp, + } + } + + /// Returns the individuals field of a [`GopTimeCode`]. + /// + /// # Safety + /// + /// The fields other than [`Timestamp`] may not be accurate if it is changed using + /// [`timestamp_mut`](GopTimeCode::timestamp_mut). + pub unsafe fn as_raw_parts(&self) -> (bool, u8, u8, u8, u8, Timestamp) { + let GopTimeCode { + drop_frame, + time_code_hours, + time_code_minutes, + time_code_seconds, + time_code_pictures, + timestamp, + } = *self; + + ( + drop_frame, + time_code_hours, + time_code_minutes, + time_code_seconds, + time_code_pictures, + timestamp, + ) + } +} diff --git a/src/rust/lib_ccxr/src/util/mod.rs b/src/rust/lib_ccxr/src/util/mod.rs index 01f9662df..ff414cb78 100644 --- a/src/rust/lib_ccxr/src/util/mod.rs +++ b/src/rust/lib_ccxr/src/util/mod.rs @@ -3,3 +3,17 @@ pub mod bits; pub mod levenshtein; pub mod log; +pub mod time; + +use std::os::raw::c_char; + +/// Helper function that converts a Rust-String (`string`) to C-String (`buffer`). +/// +/// # Safety +/// +/// `buffer` must have enough allocated space for `string` to fit. +pub fn write_string_into_pointer(buffer: *mut c_char, string: &str) { + let buffer = unsafe { std::slice::from_raw_parts_mut(buffer as *mut u8, string.len() + 1) }; + buffer[..string.len()].copy_from_slice(string.as_bytes()); + buffer[string.len()] = b'\0'; +} diff --git a/src/rust/lib_ccxr/src/util/time.rs b/src/rust/lib_ccxr/src/util/time.rs new file mode 100644 index 000000000..990cbf3c0 --- /dev/null +++ b/src/rust/lib_ccxr/src/util/time.rs @@ -0,0 +1,35 @@ +//! Provides Rust equivalent code for functions in `utility.c` involves time operations. Uses Rust-native types as input and output. + +use crate::time::units::{Timestamp, TimestampError, TimestampFormat}; + +/// Rust equivalent for `timestamp_to_srttime` function in C. +/// Uses Rust-native types as input and output. +pub fn timestamp_to_srttime( + timestamp: Timestamp, + buffer: &mut String, +) -> Result<(), TimestampError> { + timestamp.write_srt_time(buffer) +} + +/// Rust equivalent for `timestamp_to_vtttime` function in C. +/// Uses Rust-native types as input and output. +pub fn timestamp_to_vtttime( + timestamp: Timestamp, + buffer: &mut String, +) -> Result<(), TimestampError> { + timestamp.write_vtt_time(buffer) +} + +/// Rust equivalent for `millis_to_date` function in C. Uses Rust-native types as input and output. +pub fn millis_to_date( + timestamp: Timestamp, + buffer: &mut String, + date_format: TimestampFormat, +) -> Result<(), TimestampError> { + timestamp.write_formatted_time(buffer, date_format) +} + +/// Rust equivalent for `stringztoms` function in C. Uses Rust-native types as input and output. +pub fn stringztoms(s: &str) -> Option { + Timestamp::parse_optional_hhmmss_from_str(s).ok() +} diff --git a/src/rust/src/libccxr_exports/mod.rs b/src/rust/src/libccxr_exports/mod.rs index 7180626f6..eb869a4c9 100644 --- a/src/rust/src/libccxr_exports/mod.rs +++ b/src/rust/src/libccxr_exports/mod.rs @@ -1,5 +1,7 @@ //! Provides C-FFI functions that are direct equivalent of functions available in C. +pub mod time; + use crate::ccx_s_options; use lib_ccxr::util::log::*; use lib_ccxr::util::{bits::*, levenshtein::*}; diff --git a/src/rust/src/libccxr_exports/time.rs b/src/rust/src/libccxr_exports/time.rs new file mode 100644 index 000000000..b83e109cc --- /dev/null +++ b/src/rust/src/libccxr_exports/time.rs @@ -0,0 +1,125 @@ +use crate::bindings::*; + +use std::ffi::CStr; +use std::os::raw::{c_char, c_int}; + +use lib_ccxr::time::units::*; +use lib_ccxr::util::{time::*, write_string_into_pointer}; + +/// Rust equivalent for `timestamp_to_srttime` function in C. Uses C-native types as input and +/// output. +/// +/// # Safety +/// +/// `buffer` must have enough allocated space for the formatted `timestamp` to fit. +#[no_mangle] +pub extern "C" fn ccxr_timestamp_to_srttime(timestamp: u64, buffer: *mut c_char) { + let mut s = String::new(); + let timestamp = Timestamp::from_millis(timestamp as i64); + + let _ = timestamp_to_srttime(timestamp, &mut s); + + write_string_into_pointer(buffer, &s); +} + +/// Rust equivalent for `timestamp_to_vtttime` function in C. Uses C-native types as input and +/// output. +/// +/// # Safety +/// +/// `buffer` must have enough allocated space for the formatted `timestamp` to fit. +#[no_mangle] +pub extern "C" fn ccxr_timestamp_to_vtttime(timestamp: u64, buffer: *mut c_char) { + let mut s = String::new(); + let timestamp = Timestamp::from_millis(timestamp as i64); + + let _ = timestamp_to_vtttime(timestamp, &mut s); + + write_string_into_pointer(buffer, &s); +} + +/// Rust equivalent for `millis_to_date` function in C. Uses C-native types as input and output. +/// +/// # Safety +/// +/// `buffer` must have enough allocated space for the formatted `timestamp` to fit. +#[no_mangle] +pub extern "C" fn ccxr_millis_to_date( + timestamp: u64, + buffer: *mut c_char, + date_format: ccx_output_date_format, + millis_separator: c_char, +) { + let mut s = String::new(); + let timestamp = Timestamp::from_millis(timestamp as i64); + let date_format = match date_format { + ccx_output_date_format_ODF_NONE => TimestampFormat::None, + ccx_output_date_format_ODF_HHMMSS => TimestampFormat::HHMMSS, + ccx_output_date_format_ODF_HHMMSSMS => TimestampFormat::HHMMSSFFF, + ccx_output_date_format_ODF_SECONDS => TimestampFormat::Seconds { + millis_separator: millis_separator as u8 as char, + }, + ccx_output_date_format_ODF_DATE => TimestampFormat::Date { + millis_separator: millis_separator as u8 as char, + }, + _ => TimestampFormat::None, + }; + + let _ = millis_to_date(timestamp, &mut s, date_format); + + write_string_into_pointer(buffer, &s); +} + +/// Rust equivalent for `stringztoms` function in C. Uses C-native types as input and output. +/// +/// # Safety +/// +/// `s` must contain valid utf-8 data and have a null terminator at the end of the string. +#[no_mangle] +pub unsafe extern "C" fn ccxr_stringztoms(s: *const c_char, bt: *mut ccx_boundary_time) -> c_int { + let s = CStr::from_ptr(s) + .to_str() + .expect("Failed to convert buffer `s` into a &str"); + + let option_timestamp = stringztoms(s); + + if let Some(timestamp) = option_timestamp { + if let Ok((h, m, s, _)) = timestamp.as_hms_millis() { + (*bt).set = 1; + (*bt).hh = h.into(); + (*bt).mm = m.into(); + (*bt).ss = s.into(); + (*bt).time_in_ms = (timestamp.millis() / 1000) * 1000; + return 0; + } + }; + + -1 +} + +/// Rust equivalent for `millis_to_time` function in C. Uses C-native types as input and output. +/// +/// # Safety +/// +/// Must ensure all passed pointers are valid and non-null. +#[no_mangle] +pub unsafe extern "C" fn ccxr_millis_to_time( + milli: i64, + hours: *mut u32, + minutes: *mut u32, + seconds: *mut u32, + ms: *mut u32, +) { + let ms_value = (milli % 1000) as u32; // milliseconds + let mut remaining = (milli - ms_value as i64) / 1000; // Remainder, in seconds + let seconds_value = (remaining % 60) as u32; + remaining = (remaining - seconds_value as i64) / 60; // Remainder, in minutes + let minutes_value = (remaining % 60) as u32; + remaining = (remaining - minutes_value as i64) / 60; // Remainder, in hours + let hours_value = remaining as u32; + + *hours = hours_value; + *minutes = minutes_value; + *seconds = seconds_value; + *ms = ms_value; +} From 34bb9dd20d09b2fd9745595f2477bdb0459665fa Mon Sep 17 00:00:00 2001 From: Ishan Grover <123376573+IshanGrover2004@users.noreply.github.com> Date: Wed, 17 Jul 2024 08:47:57 +0530 Subject: [PATCH 26/27] [FEATURE]: Create Docker image for CCExtractor (#1611) * docs: Create a README for docker image usage * docs: Update `COMPILATION.md` for adding docker instruction * docs: Add detailed docker building & usage guide * feat: Add dockerfile * feat: Make dockerfile to build CCExtractor * fix: dockerfile * feat: Optimize docker image size * docs: fix some commands usage * docs: Mention docker image creation in CHANGES.txt * docs: Update readme to remove dockerhub method --- docker/README.md | 61 +++++++++++++++++++++++++++++++++++++++++++++ docker/dockerfile | 48 +++++++++++++++++++++++++++++++++++ docs/CHANGES.TXT | 1 + docs/COMPILATION.MD | 3 +++ 4 files changed, 113 insertions(+) create mode 100644 docker/README.md create mode 100644 docker/dockerfile diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 000000000..60fdb744e --- /dev/null +++ b/docker/README.md @@ -0,0 +1,61 @@ +# CCExtractor Docker image + +This dockerfile prepares a minimalist Docker image with CCExtractor. It compiles CCExtractor from sources following instructions from the [Compilation Guide](https://github.com/CCExtractor/ccextractor/blob/master/docs/COMPILATION.MD). + +You can install the latest build of this image by running `docker pull CCExtractor/ccextractor` + +## Build + +You can build the Docker image directly from the Dockerfile provided in [docker](https://github.com/CCExtractor/ccextractor/tree/master/docker) directory of CCExtractor source + +```bash +$ git clone https://github.com/CCExtractor/ccextractor.git && cd ccextractor +$ cd docker/ +$ docker build -t ccextractor . +``` + +## Usage + +The CCExtractor Docker image can be used in several ways, depending on your needs. + +```bash +# General usage +$ docker run ccextractor:latest +``` + +1. Process a local file & use `-o` flag + +To process a local video file, mount a directory containing the input file inside the container: + +```bash +# Use `-o` to specifying output file +$ docker run --rm -v $(pwd):$(pwd) -w $(pwd) ccextractor:latest input.mp4 -o output.srt + +# Alternatively use `--stdout` feature +$ docker run --rm -v $(pwd):$(pwd) -w $(pwd) ccextractor:latest input.mp4 --stdout > output.srt +``` + +Run this command from where your input video file is present, and change `input.mp4` & `output.srt` with the actual name of files. + +2. Enter an interactive environment + +If you need to run CCExtractor with additional options or perform other tasks within the container, you can enter an interactive environment: +bash + +```bash +$ docker run --rm -it --entrypoint='sh' ccextractor:latest +``` + +This will start a Bash shell inside the container, allowing you to run CCExtractor commands manually or perform other operations. + +### Example + +I run help command in image built from `dockerfile` + +```bash +$ docker build -t ccextractor . +$ docker run --rm ccextractor:latest --help +``` + +This will show the `--help` message of CCExtractor tool +From there you can see all the features and flags which can be used. diff --git a/docker/dockerfile b/docker/dockerfile new file mode 100644 index 000000000..98ac85d0f --- /dev/null +++ b/docker/dockerfile @@ -0,0 +1,48 @@ +FROM alpine:latest as base + +FROM base as builder + +RUN apk add --no-cache --update git curl gcc cmake glew glfw \ + tesseract-ocr-dev leptonica-dev clang-dev llvm-dev make pkgconfig \ + zlib-dev libpng-dev libjpeg-turbo-dev openssl-dev freetype-dev libxml2-dev + +RUN cd && git clone https://github.com/gpac/gpac +WORKDIR root/gpac/ +RUN ./configure && make && make install-lib && cd && rm -rf /root/gpac + +WORKDIR /root +RUN git clone https://github.com/CCExtractor/ccextractor.git +RUN apk add bash cargo +RUN export LIB_CLANG_PATH=$(find / -name 'libclang*.so*' 2>/dev/null | grep -v 'No such file' | head -n 1 | xargs dirname) +RUN cd /root/ccextractor/linux && ./pre-build.sh && ./build + +RUN cp /root/ccextractor/linux/ccextractor /ccextractor && rm -rf ~/ccextractor + +FROM base as final + +COPY --from=builder /lib/ld-musl-x86_64.so.1 /lib/ +COPY --from=builder /usr/lib/libtesseract.so.5 /usr/lib/ +COPY --from=builder /usr/lib/libleptonica.so.6 /usr/lib/ +COPY --from=builder /usr/local/lib/libgpac.so.12 /usr/local/lib/ +COPY --from=builder /usr/lib/libstdc++.so.6 /usr/lib/ +COPY --from=builder /usr/lib/libgcc_s.so.1 /usr/lib/ +COPY --from=builder /usr/lib/libgomp.so.1 /usr/lib/ +COPY --from=builder /usr/lib/libpng16.so.16 /usr/lib/ +COPY --from=builder /usr/lib/libjpeg.so.8 /usr/lib/ +COPY --from=builder /usr/lib/libgif.so.7 /usr/lib/ +COPY --from=builder /usr/lib/libtiff.so.6 /usr/lib/ +COPY --from=builder /usr/lib/libwebp.so.7 /usr/lib/ +COPY --from=builder /usr/lib/libwebpmux.so.3 /usr/lib/ +COPY --from=builder /lib/libz.so.1 /lib/ +COPY --from=builder /lib/libssl.so.3 /lib/ +COPY --from=builder /lib/libcrypto.so.3 /lib/ +COPY --from=builder /usr/lib/liblzma.so.5 /usr/lib/ +COPY --from=builder /usr/lib/libzstd.so.1 /usr/lib/ +COPY --from=builder /usr/lib/libsharpyuv.so.0 /usr/lib/ + +COPY --from=builder /ccextractor / + +ENTRYPOINT [ "/ccextractor" ] + +CMD [ "/ccextractor" ] + diff --git a/docs/CHANGES.TXT b/docs/CHANGES.TXT index a722bfbe0..bf6b6503a 100644 --- a/docs/CHANGES.TXT +++ b/docs/CHANGES.TXT @@ -1,5 +1,6 @@ 0.95 (to be released) ----------------- +- New: Create a Docker image to simplify the CCExtractor usage without any environmental hustle (#1611) - New: Add time units module in lib_ccxr (#1623) - New: Add bits and levenshtein module in lib_ccxr (#1627) - New: Add constants module in lib_ccxr (#1624) diff --git a/docs/COMPILATION.MD b/docs/COMPILATION.MD index a919164ac..8a8f1d0a5 100644 --- a/docs/COMPILATION.MD +++ b/docs/COMPILATION.MD @@ -10,6 +10,9 @@ Clone the latest repository from Github git clone https://github.com/CCExtractor/ccextractor.git ``` +## Docker +You can now use docker image to build latest source of CCExtractor without any environmental hustle. Follow these [instructions](https://github.com/CCExtractor/ccextractor/tree/master/docker/README.md) for building docker image & usage of it. + ## Linux 1. Make sure all the dependencies are met. From 90204d4cc60ec5e583c304fc782c06bf594b98bf Mon Sep 17 00:00:00 2001 From: Ishan Grover <123376573+IshanGrover2004@users.noreply.github.com> Date: Wed, 7 Aug 2024 15:38:24 +0530 Subject: [PATCH 27/27] [DOCS] Add C to Rust code migration guide (#1629) * docs: Add c-to-migration guide docs * docs: Update suggested typos in `docs/Rust_migration_guide.md` Co-authored-by: Punit Lodha <48253287+PunitLodha@users.noreply.github.com> --------- Co-authored-by: Punit Lodha <48253287+PunitLodha@users.noreply.github.com> --- docs/Rust_migration_guide.md | 71 ++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 docs/Rust_migration_guide.md diff --git a/docs/Rust_migration_guide.md b/docs/Rust_migration_guide.md new file mode 100644 index 000000000..17bb14dcb --- /dev/null +++ b/docs/Rust_migration_guide.md @@ -0,0 +1,71 @@ +# C to Rust Migration Guide + +## Porting C Functions to Rust + +This guide outlines the process of migrating C functions to Rust while maintaining compatibility with existing C code. + +### Step 1: Identify the C Function + +First, identify the C function you want to port. For example, let's consider a function named `net_send_cc()` in a file called `networking.c`: + +```c +void net_send_cc() { + // Some C code +} +``` + +### Step 2: Create a Pure Rust Equivalent + +Write an equivalent function in pure Rust within the `lib_ccxr` module: + +```rust +fn net_send_cc() { + // Rust equivalent code to `net_send_cc` function in `networking.c` +} +``` + +### Step 3: Create a C-Compatible Rust Function + +In the `libccxr_exports` module, create a new function that will be callable from C: + +```rust +#[no_mangle] +pub extern "C" fn ccxr_net_send_cc() { + net_send_cc() // Call the pure Rust function +} +``` + +### Step 4: Declare the Rust Function in C + +In the original C file (`networking.c`), declare the Rust function as an external function: + +```rust +extern void ccxr_net_send_cc(); +``` + +### Step 5: Modify the Original C Function + +Update the original C function to use the Rust implementation when available: + +```c +void net_send_cc() { + #ifndef DISABLE_RUST + return ccxr_net_send_cc(); // Use the Rust implementation + #else + // Original C code + #endif +} +``` + +## Rust module system + +- `lib_ccxr` crate -> **The Idiomatic Rust layer** + + - Path: `src/rust/lib_ccxr` + - This layer will contain the migrated idiomatic Rust. It will have complete documentation and tests. + +- `libccxr_exports` module -> **The C-like Rust layer** + + - Path: `src/rust/src/libccxr_exports` + - This layer will have function names the same as defined in C but with the prefix `ccxr_`. These are the functions defined in the `lib_ccx` crate under appropriate modules. And these functions will be provided to the C library. + - Ex: `extern "C" fn ccxr_() {}`