[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
This commit is contained in:
Ishan Grover
2024-07-17 03:34:48 +05:30
committed by GitHub
parent 8e4c07ed97
commit 8d9bf42be2
15 changed files with 1253 additions and 119 deletions

View File

@@ -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)

View File

@@ -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

View File

@@ -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);

View File

@@ -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];

View File

@@ -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);

316
src/rust/Cargo.lock generated
View File

@@ -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",
]
@@ -255,10 +263,16 @@ dependencies = [
]
[[package]]
name = "lazy_static"
version = "1.4.0"
name = "itoa"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
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"
@@ -335,19 +352,25 @@ dependencies = [
]
[[package]]
name = "num-traits"
version = "0.2.16"
name = "num-conv"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
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"
@@ -524,10 +553,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustix"
version = "0.38.13"
name = "rustc_version"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7db8590df6dfcd144d22afd1b83b36c21a18d7cbc1dc4bb5295a8712e9eb662"
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
dependencies = [
"semver",
]
[[package]]
name = "rustix"
version = "0.38.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
dependencies = [
"bitflags 2.6.0",
"errno",
@@ -551,30 +589,36 @@ dependencies = [
]
[[package]]
name = "serde"
version = "1.0.188"
name = "semver"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
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.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 = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
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"

View File

@@ -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"

View File

@@ -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 = []

View File

@@ -1,2 +1,3 @@
pub mod common;
pub mod time;
pub mod util;

View File

@@ -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>`](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;

View File

@@ -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<Timestamp, TimestampError> {
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<String, TimestampError> {
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<String, TimestampError> {
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<String, TimestampError> {
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<String, TimestampError> {
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<String, TimestampError> {
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<Timestamp, TimestampError> {
let mut numbers = input
.split(':')
.map(|x| x.parse::<u8>().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<GopTimeCode> {
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,
)
}
}

View File

@@ -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';
}

View File

@@ -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> {
Timestamp::parse_optional_hhmmss_from_str(s).ok()
}

View File

@@ -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::*};

View File

@@ -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;
}