nx_recording.nx source
↩ module page · 67 lines · 2617 B
1// nx_recording.nx -- LIVE vs RECORDING/advertisement classifier over a
2// sequence of perceptual frame fingerprints. R1 of the MEDIA-STUDIO arc.
3//
4// A "recording" (a slate, advertisement, or a frozen/looping clip put up in
5// place of a live feed) shows one of two temporal signatures:
6// STATIC-HOLD : a sustained run of near-identical frames (a frozen image
7// held for >= hold_frames frames). One static pair is just
8// dead-air (R0); a long HOLD is a recording.
9// LOOP : the same frame recurs after a gap of >= min_period frames
10// (the clip is looping).
11// Either signature => RECORDING; otherwise LIVE.
12//
13// Fingerprints are 64-bit perceptual hashes (nx_phash aHash/dHash); "near-
14// identical" = Hamming distance <= near, reusing nx_simhash's Hamming kernel.
15// All thresholds are CALLER-supplied (data-driven, no magic numbers here).
16//
17// genealogy_id: perceptual_hash_temporal_recurrence (record-hint, unverified)
18// lineage_id: frame_fingerprint_sequence + run_length + periodic_recurrence
19// nx_safety_envelope:
20// intended_use: "Flag recorded/looped/advertisement segments in a stream
21// so the trim planner (R3) can cut them."
22// verdict: NOT_YET_EVALUATED
23// license_tier: ORIGINAL
24
25import "syscalls.nx"
26import "nx_simhash.nx"
27
28const NX_REC_LIVE: i64 = 0
29const NX_REC_RECORDING: i64 = 1
30
31// Longest run of consecutive near-identical frames (Hamming <= near).
32func nx_rec_max_hold(fps: *i64, n: i64, near: i64) -> i64 {
33 if n <= 0 { return 0 }
34 var best: i64 = 1
35 var run: i64 = 1
36 var i: i64 = 1
37 while i < n {
38 let d: i64 = nx_simhash_hamming(fps[i], fps[i - 1])
39 if d <= near { run = run + 1 }
40 if d > near { run = 1 }
41 if run > best { best = run }
42 i = i + 1
43 }
44 return best
45}
46
47// Does any frame recur at a gap of >= min_period frames? 1 = loop, 0 = none.
48func nx_rec_has_loop(fps: *i64, n: i64, near: i64, min_period: i64) -> i64 {
49 var i: i64 = 0
50 while i < n {
51 var j: i64 = i + min_period
52 while j < n {
53 if nx_simhash_hamming(fps[i], fps[j]) <= near { return 1 }
54 j = j + 1
55 }
56 i = i + 1
57 }
58 return 0
59}
60
61// Classify a fingerprint sequence: RECORDING if a sustained hold OR a loop,
62// else LIVE.
63func nx_rec_classify(fps: *i64, n: i64, near: i64, hold_frames: i64, min_period: i64) -> i64 {
64 if nx_rec_max_hold(fps, n, near) >= hold_frames { return NX_REC_RECORDING }
65 if nx_rec_has_loop(fps, n, near, min_period) == 1 { return NX_REC_RECORDING }
66 return NX_REC_LIVE
67}