>From 36cc44569a898c8401944bc16b791632fd4ac985 Mon Sep 17 00:00:00 2001
From: Dave Rice <dave at dericed.com>
Date: Mon, 30 Jun 2025 00:00:00 +0200
Subject: [PATCH 4/7] 32-bit timecode to 64-bit RFC 5484 timecode functions
---
libavutil/timecode.c | 104 +++++++++++++++++++++++++++++++++++++++++++
libavutil/timecode.h | 22 +++++++++
2 files changed, 126 insertions(+)
diff --git a/libavutil/timecode.c b/libavutil/timecode.c
index bca16b6ac2..81fb66a5e4 100644
--- a/libavutil/timecode.c
+++ b/libavutil/timecode.c
@@ -243,3 +243,107 @@ int av_timecode_init_from_string(AVTimecode *tc,
AVRational rate, const char *st
return av_timecode_init_from_components(tc, rate, flags, hh, mm, ss, ff,
log_ctx);
}
+
+static int bcd_to_int(int bcd) {
+ return ((bcd >> 4) & 0xF) * 10 + (bcd & 0xF);
+}
+
+uint64_t av_timecode_expand_to_64bit(uint32_t tc32)
+{
+ uint64_t tc64 = 0;
+
+ int hours_bcd = tc32 & 0x3F; // bits 0-5
+ int bgf1 = (tc32 >> 6) & 0x1; // bit 6
+ int bgf2 = (tc32 >> 7) & 0x1; // bit 7
+ int minutes_bcd = (tc32 >> 8) & 0x7F; // bits 8-14
+ int bgf0 = (tc32 >> 15) & 0x1; // bit 15
+ int seconds_bcd = (tc32 >> 16) & 0x7F; // bits 16-22
+ int frames_bcd = (tc32 >> 24) & 0x3F; // bits 24-29
+ int drop = (tc32 >> 30) & 0x1; // bit 30
+ int color = (tc32 >> 31) & 0x1; // bit 31
+
+ int hours = bcd_to_int(hours_bcd);
+ int minutes = bcd_to_int(minutes_bcd);
+ int seconds = bcd_to_int(seconds_bcd);
+ int frames = bcd_to_int(frames_bcd);
+
+ // Units and tens
+ int uh = hours % 10, th = hours / 10;
+ int um = minutes % 10, tm = minutes / 10;
+ int us = seconds % 10, ts = seconds / 10;
+ int uf = frames % 10, tf = frames / 10;
+
+ // Assign bits as per RFC 5484 layout
+ tc64 |= (uint64_t)(uf & 0xF) << 0; // Units of frames
+ tc64 |= 0 << 4; // First binary group
+ tc64 |= (uint64_t)(tf & 0x3) << 8; // Tens of frames (2 bits)
+ tc64 |= (uint64_t)drop << 10; // Drop frame flag
+ tc64 |= (uint64_t)color << 11; // Color frame flag
+ tc64 |= 0 << 12; // Second binary group
+
+ tc64 |= (uint64_t)(us & 0xF) << 16; // Units of seconds
+ tc64 |= 0 << 20; // Third binary group
+ tc64 |= (uint64_t)(ts & 0x7) << 24; // Tens of seconds
+ tc64 |= 0 << 27; // Polarity correction
+ tc64 |= 0 << 28; // Fourth binary group
+
+ tc64 |= (uint64_t)(um & 0xF) << 32; // Units of minutes
+ tc64 |= (uint64_t)0 << 36; // Fifth binary group
+ tc64 |= (uint64_t)(tm & 0x7) << 40; // Tens of minutes
+ tc64 |= (uint64_t)bgf0 << 43; // BGF0
+ tc64 |= (uint64_t)0 << 44; // Sixth binary group
+
+ tc64 |= (uint64_t)(uh & 0xF) << 48; // Units of hours
+ tc64 |= (uint64_t)0 << 52; // Seventh binary group
+ tc64 |= (uint64_t)(th & 0x3) << 56; // Tens of hours
+ tc64 |= (uint64_t)bgf1 << 58; // BGF1
+ tc64 |= (uint64_t)bgf2 << 59; // BGF2
+ tc64 |= (uint64_t)0 << 60; // Eighth binary group
+
+ return tc64;
+}
+
+static int int_to_bcd(int val) {
+ return ((val / 10) << 4) | (val % 10);
+}
+
+uint32_t av_timecode_parse_from_64bit(uint64_t tc64)
+{
+ uint32_t tc32 = 0;
+
+ int uf = (tc64 >> 0) & 0xF; // Ones of frames
+ int tf = (tc64 >> 8) & 0x3; // Tens of frames
+ int drop = (tc64 >> 10) & 0x1;
+ int color= (tc64 >> 11) & 0x1;
+
+ int us = (tc64 >> 16) & 0xF; // Ones of seconds
+ int ts = (tc64 >> 24) & 0x7; // Tens of seconds
+
+ int um = (tc64 >> 32) & 0xF; // Ones of minutes
+ int tm = (tc64 >> 40) & 0x7; // Tens of minutes
+ int bgf0 = (tc64 >> 43) & 0x1;
+
+ int uh = (tc64 >> 48) & 0xF; // Ones of hours
+ int th = (tc64 >> 56) & 0x3; // Tens of hours
+ int bgf1 = (tc64 >> 58) & 0x1;
+ int bgf2 = (tc64 >> 59) & 0x1;
+
+ int hours = int_to_bcd(th * 10 + uh);
+ int minutes = int_to_bcd(tm * 10 + um);
+ int seconds = int_to_bcd(ts * 10 + us);
+ int frames = int_to_bcd(tf * 10 + uf);
+
+ // Assemble tc32 using the FFmpeg SMPTE 32-bit format
+ tc32 |= (hours & 0x3F) << 0; // bits 0-5: hours (BCD)
+ tc32 |= (bgf1 & 0x1) << 6; // bit 6: BGF1
+ tc32 |= (bgf2 & 0x1) << 7; // bit 7: BGF2 (or FIELD)
+ tc32 |= (minutes & 0x7F) << 8; // bits 8-14: minutes (BCD)
+ tc32 |= (bgf0 & 0x1) << 15; // bit 15: BGF0
+ tc32 |= (seconds & 0x7F) << 16; // bits 16-22: seconds (BCD)
+ tc32 |= 0 << 23; // bit 23: FIELD (set to 0)
+ tc32 |= (frames & 0x3F) << 24; // bits 24-29: frames (BCD)
+ tc32 |= (drop & 0x1) << 30; // bit 30: drop frame flag
+ tc32 |= (color & 0x1) << 31; // bit 31: color frame flag
+
+ return tc32;
+}
diff --git a/libavutil/timecode.h b/libavutil/timecode.h
index fe0fc83576..81713a9adf 100644
--- a/libavutil/timecode.h
+++ b/libavutil/timecode.h
@@ -196,4 +196,26 @@ int av_timecode_init_from_string(AVTimecode *tc,
AVRational rate, const char *st
*/
int av_timecode_check_frame_rate(AVRational rate);
+/**
+ * Convert a 32-bit SMPTE 12M timecode to 64-bit SMPTE 12M/RFC 5484 format.
+ *
+ * This maps the timecode as described in RFC 5484 Section 6.2,
+ * expanding BCD-encoded time values into bit fields without the sync word.
+ *
+ * @param tc32 The 32-bit SMPTE timecode (from DeckLink or
av_timecode_get_smpte)
+ * @return The 64-bit SMPTE 12M timecode format (without sync word)
+ */
+uint64_t av_timecode_expand_to_64bit(uint32_t tc32);
+
+/**
+ * Convert a 64-bit SMPTE 12M/RFC 5484 timecode to 32-bit SMPTE format.
+ *
+ * This reconstructs the packed 32-bit SMPTE timecode (DeckLink-style or
FFmpeg output)
+ * from a full 64-bit representation.
+ *
+ * @param tc64 The 64-bit timecode value in RFC 5484 / SMPTE 12M format
(without sync word)
+ * @return A 32-bit SMPTE timecode
+ */
+uint32_t av_timecode_parse_from_64bit(uint64_t tc64);
+
#endif /* AVUTIL_TIMECODE_H */
--
2.46.0.windows.1
_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]