Skip to content

Instantly share code, notes, and snippets.

@TravisMullen
Last active November 7, 2020 04:46
Show Gist options
  • Save TravisMullen/d6de20c93621fb43b4dfdbb9503ded8d to your computer and use it in GitHub Desktop.
Save TravisMullen/d6de20c93621fb43b4dfdbb9503ded8d to your computer and use it in GitHub Desktop.
Calculate positions offset value for each frame provided.
const MODULE_NAME = 'Calculate positions offset value for each frame provided.'
/**
* Convert time into seconds which is the smallest increment of time encoded into the video.
* @param {string} time Time in the format of HH:MM:SS using colons as the delimiter.
* @return {number} Time converted to seconds.
*/
const seconds = time => {
const [hours,minutes,seconds] = time.split(':')
return parseInt((((parseInt(hours) * 60) + parseInt(minutes)) * 60) + parseInt(seconds))
}
// const seconds = (minutes,seconds) => (minutes*60) + seconds
/**
* Determine the difference between embedded timestamp and actually playback time from video display.
* @param {string} videoindex Time of video playback position indicated by the software streaming the video file.
* @param {string} timestamp Time of video as indicated by the timestamp encoded into the visual frame.
* @return {number} Offset between the file's playback video time and the encoded time from the original video.
*/
const marker = (videoindex,timestamp) => timestamp - videoindex
/** Calculate position offset value from a single frame. */
const calculate = (videoindex,timestamp) => (
marker(
seconds(videoindex),
seconds(timestamp)
)
)
/** Calculate an series of positions offset values from an arrays of frames. */
const calculateAll = arr => {
const offsets = []
console.time(MODULE_NAME)
for (item of arr) {
console.count('calculate frame')
const [videoindex,timestamp] = item
console.log(`video tracking index: ${videoindex} s, encoded timestamp: ${timestamp} s`)
console.log(calculate(videoindex,timestamp))
}
console.timeEnd(MODULE_NAME)
}
/**
* @example
*
* The following data set is taken from body-worn camera of:
* Deputy J. McClellan <8926> of the Orange County Sheriff's Office ("OCSO")
* from an arrest made on April 1, 2019.
*
* The OCSO Records Identification Section ("Records Section") provided a video
* which attempts to hide that the Deputy deactivated his body-worn camera.
*
* The Records Section attempts to obscure that two clips are pasted together
* by claiming a necessary full-frame redaction, instead of redacting only a portion of the frame.
* Generally, it is common practice to use a blur filter so that if a grouping of frames is removed
* it can allows for the human eye can to detect any clipping or jumping. It's a good faith best practice.
* In this case, the first section of full-frame redaction ("the point of compromise")
* does not implement the blur filter, which is in fact used later on in the same video,
* but instead said section implements a black box which additionally obscures the video's native encoded timestamp.
*
* This algorithm is designed to be easily reproducible by anyone whom
* has a copy of the forged video record by stopping the playback window on any frame
* before or after the point of compromise occurs, and making a relative comparison of the two value for each frame.
*
* The following array consists of eight (8) random frames before the point of compromise starts,
* and ten (10) random frames after the point of compromise ends.
*
*/
calculateAll([
[ // frame 1
'0:0:0', // time of video playback of the file.
'06:44:16' // time as encoded into video stream.
],
['0:0:3', '06:44:19'],
['0:0:14', '06:44:30'],
['0:0:27', '06:44:43'],
['0:1:20', '06:45:36'],
['0:1:27', '06:45:44'],
['0:2:31', '06:46:48'],
['0:3:03', '06:47:19'],
// ** redaction occurs masking encoded timestamps ** //
['0:15:54', '07:00:09'],
['0:17:13', '07:01:28'],
['0:18:42', '07:02:57'],
['0:19:26', '07:03:41'],
['0:21:36', '07:05:51'],
['0:23:29', '07:07:44'],
['0:25:05', '07:09:20'],
['0:26:27', '07:10:43'],
['0:30:17', '07:14:32'],
['0:31:02', '07:15:17'],
])
@TravisMullen
Copy link
Author

calculate frame: 1
video tracking index: 0:0:0 s, encoded timestamp: 06:44:16 s
24256
calculate frame: 2
video tracking index: 0:0:3 s, encoded timestamp: 06:44:19 s
24256
calculate frame: 3
video tracking index: 0:0:14 s, encoded timestamp: 06:44:30 s
24256
calculate frame: 4
video tracking index: 0:0:27 s, encoded timestamp: 06:44:43 s
24256
calculate frame: 5
video tracking index: 0:1:20 s, encoded timestamp: 06:45:36 s
24256
calculate frame: 6
video tracking index: 0:1:27 s, encoded timestamp: 06:45:44 s
24257
calculate frame: 7
video tracking index: 0:2:31 s, encoded timestamp: 06:46:48 s
24257
calculate frame: 8
video tracking index: 0:3:03 s, encoded timestamp: 06:47:19 s
24256
calculate frame: 9
video tracking index: 0:15:54 s, encoded timestamp: 07:00:09 s
24255
calculate frame: 10
video tracking index: 0:17:13 s, encoded timestamp: 07:01:28 s
24255
calculate frame: 11
video tracking index: 0:18:42 s, encoded timestamp: 07:02:57 s
24255
calculate frame: 12
video tracking index: 0:19:26 s, encoded timestamp: 07:03:41 s
24255
calculate frame: 13
video tracking index: 0:21:36 s, encoded timestamp: 07:05:51 s
24255
calculate frame: 14
video tracking index: 0:23:29 s, encoded timestamp: 07:07:44 s
24255
calculate frame: 15
video tracking index: 0:25:05 s, encoded timestamp: 07:09:20 s
24255
calculate frame: 16
video tracking index: 0:26:27 s, encoded timestamp: 07:10:43 s
24256
calculate frame: 17
video tracking index: 0:30:17 s, encoded timestamp: 07:14:32 s
24255
calculate frame: 18
video tracking index: 0:31:02 s, encoded timestamp: 07:15:17 s
24255

Calculate positions offset value for each frame provided.: 2.64013671875 ms

@TravisMullen
Copy link
Author

Prior to the point of compromise the resulting value is either 24256 or 24257.
After the point of compromise the resulting value is either 24255 or 24256.
The foregoing results prove that the video has been manipulated because the axis of shifts by a full second
indicating either 500-999ms was removed, or more likely, two separate sections were combined and aligned using the human eye.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment