<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>http://wiki.staging.zoneminder.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Kitkat</id>
	<title>ZoneMinder Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="http://wiki.staging.zoneminder.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Kitkat"/>
	<link rel="alternate" type="text/html" href="http://wiki.staging.zoneminder.com/Special:Contributions/Kitkat"/>
	<updated>2026-04-20T00:02:31Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.37.1</generator>
	<entry>
		<id>http://wiki.staging.zoneminder.com/index.php?title=How_to_use_a_video_file_as_a_Source&amp;diff=16746</id>
		<title>How to use a video file as a Source</title>
		<link rel="alternate" type="text/html" href="http://wiki.staging.zoneminder.com/index.php?title=How_to_use_a_video_file_as_a_Source&amp;diff=16746"/>
		<updated>2021-12-03T15:05:01Z</updated>

		<summary type="html">&lt;p&gt;Kitkat: New code to allow the use of  Event IDs; better Testing and Usage instructions; general tidying up&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;There was [https://forums.zoneminder.com/viewtopic.php?f=43&amp;amp;t=31176 a question on the forums] a while ago asking whether it was possible to test zones against stored events, which interested me, and I&amp;#039;ve cobbled together a method of doing it with PHP and FFMpeg. You can use it to stream a ZM event or a video file.&lt;br /&gt;
&lt;br /&gt;
=== How it works ===&lt;br /&gt;
&lt;br /&gt;
FFmpeg does all the real work, reading a video file at real-time speed and outputting it to the client. The rest of the code is a wrapper around the FFmpeg command, validating parameters and locating the file to be streamed.&lt;br /&gt;
&lt;br /&gt;
=== Code ===&lt;br /&gt;
&lt;br /&gt;
Create a file named &amp;lt;kbd&amp;gt;replay-test.php&amp;lt;/kbd&amp;gt; in your server&amp;#039;s web root (not the ZM root) and paste this into it. You shouldn&amp;#039;t have to change anything, just copy/paste/save.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;height: 300px; overflow: scroll;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?PHP&lt;br /&gt;
&lt;br /&gt;
// Usage / ZM Source syntax&lt;br /&gt;
// To stream a ZM event: http://server/replay-test.php?e=eventID&lt;br /&gt;
// To stream a video file: http://server/replay-test.php?f=/full/path/to/file.mp4&lt;br /&gt;
&lt;br /&gt;
// Source file&lt;br /&gt;
// Used only if you don&amp;#039;t set an eventID below and don&amp;#039;t&lt;br /&gt;
// pass a filename or event ID in the URL query string.&lt;br /&gt;
// Must be the /full/path/to/file.mp4&lt;br /&gt;
$infile = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// Event ID&lt;br /&gt;
// Used only if you don&amp;#039;t pass an eventID or filename in the URL query string.&lt;br /&gt;
// Use 0 for none&lt;br /&gt;
$eventID = 0;&lt;br /&gt;
&lt;br /&gt;
// Database info&lt;br /&gt;
// We need this when using event IDs.&lt;br /&gt;
// We&amp;#039;ll try to get to get it from the&lt;br /&gt;
// ZM conf files so you&amp;#039;ll only need to&lt;br /&gt;
// set it if that fails and you get an error.&lt;br /&gt;
// If you set one item then you must set all.&lt;br /&gt;
$db = array(    &amp;quot;ZM_DB_HOST&amp;quot; =&amp;gt; &amp;quot;&amp;quot;,&lt;br /&gt;
		&amp;quot;ZM_DB_NAME&amp;quot; =&amp;gt; &amp;quot;&amp;quot;,&lt;br /&gt;
		&amp;quot;ZM_DB_USER&amp;quot; =&amp;gt; &amp;quot;&amp;quot;,&lt;br /&gt;
		&amp;quot;ZM_DB_PASS&amp;quot; =&amp;gt; &amp;quot;&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
// Whether to loop the video&lt;br /&gt;
// Use -1 for infinite,&lt;br /&gt;
// 0 for single-shot,&lt;br /&gt;
// 1 for 1 loop (2 plays), etc.&lt;br /&gt;
// Anything other than -1 will throw warnings in the ZM&lt;br /&gt;
// log when the stream ends and the zmc_ process restarts.&lt;br /&gt;
$loopcount = -1;&lt;br /&gt;
&lt;br /&gt;
// Path to ffpmeg - try &amp;#039;which ffmpeg&amp;#039; at the CLI to find yours&lt;br /&gt;
$ffmpeg = &amp;quot;/usr/bin/ffmpeg&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// Path to grep&lt;br /&gt;
$grep = &amp;quot;/bin/grep&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// No configuration variables below here&lt;br /&gt;
&lt;br /&gt;
// URL parameters&lt;br /&gt;
if( !empty($_GET[&amp;#039;f&amp;#039;]) ) {&lt;br /&gt;
	$infile = $_GET[&amp;#039;f&amp;#039;];&lt;br /&gt;
	$eventID = &amp;quot;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if( !empty($_GET[&amp;#039;e&amp;#039;]) ) {&lt;br /&gt;
	$eventID = $_GET[&amp;#039;e&amp;#039;];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Got anything to do?&lt;br /&gt;
if( empty($infile) &amp;amp;&amp;amp; empty($eventID) ) {&lt;br /&gt;
	header(&amp;quot;HTTP/1.1 400 Bad Request (no filename or event ID)&amp;quot;);&lt;br /&gt;
	echo &amp;quot;No filename or event ID&amp;quot;;&lt;br /&gt;
	exit;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Get a filepath if we&amp;#039;ve got an eventID&lt;br /&gt;
if( !empty($eventID) ) {&lt;br /&gt;
	$infile = getFilenameByEventID($eventID);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Can we read the file?&lt;br /&gt;
if( empty($infile) || !is_readable($infile) ) {&lt;br /&gt;
	header(&amp;quot;HTTP/1.1 500 Internal Server Error (can&amp;#039;t read file)&amp;quot;);&lt;br /&gt;
	echo &amp;quot;Can&amp;#039;t read file &amp;#039;&amp;quot;.$infile.&amp;quot;&amp;#039;)&amp;quot;;&lt;br /&gt;
	exit;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// ffmpeg good to go?&lt;br /&gt;
if( !is_executable($ffmpeg) ) {&lt;br /&gt;
	header(&amp;quot;HTTP/1.1 500 Internal server error (can&amp;#039;t execute ffmpeg)&amp;quot;);&lt;br /&gt;
	echo &amp;quot;Can&amp;#039;t execute ffmpeg - please set the path&amp;quot;;&lt;br /&gt;
	exit;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Don&amp;#039;t let max_execution_time kill us&lt;br /&gt;
set_time_limit(0);&lt;br /&gt;
&lt;br /&gt;
// No output buffering or compression&lt;br /&gt;
// Try to cover all the bases...&lt;br /&gt;
@apache_setenv(&amp;#039;no-gzip&amp;#039;, 1);&lt;br /&gt;
@ini_set(&amp;#039;output_buffering&amp;#039;, &amp;#039;Off&amp;#039;);&lt;br /&gt;
@ini_set(&amp;#039;output_handler&amp;#039;, &amp;#039;&amp;#039;);&lt;br /&gt;
@ini_set(&amp;#039;zlib.output_compression&amp;#039;, &amp;#039;Off&amp;#039;);&lt;br /&gt;
@ob_end_flush();&lt;br /&gt;
@flush;&lt;br /&gt;
&lt;br /&gt;
// Tell the client what we&amp;#039;re sending&lt;br /&gt;
header( &amp;quot;Content-Type: video/mp4&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
// And invoke FFmpeg to send it...&lt;br /&gt;
passthru( $ffmpeg.&amp;quot; -stream_loop &amp;quot;.$loopcount.&amp;quot; -re -fflags +genpts -i &amp;#039;&amp;quot;.$infile.&amp;quot;&amp;#039; -vcodec copy -an -sn -vsync 0 -map_metadata -1 -f mp4 -movflags frag_keyframe+empty_moov - 2&amp;gt;/dev/null&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
// All done&lt;br /&gt;
&lt;br /&gt;
exit;&lt;br /&gt;
&lt;br /&gt;
function getFilenameByEventID( $eventID ) {&lt;br /&gt;
	// We&amp;#039;ll need these&lt;br /&gt;
	// Don&amp;#039;t like globals but don&amp;#039;t want to pass anything other than eventID&lt;br /&gt;
	$db = $GLOBALS[&amp;#039;db&amp;#039;];&lt;br /&gt;
	$grep = $GLOBALS[&amp;#039;grep&amp;#039;];&lt;br /&gt;
&lt;br /&gt;
	// Do we need to get database details from the .conf?&lt;br /&gt;
	if( empty($db[&amp;#039;ZM_DB_HOST&amp;#039;]) ) {&lt;br /&gt;
		if( !is_executable($grep) ) {&lt;br /&gt;
			header(&amp;quot;HTTP/1.1 500 Internal server error (can&amp;#039;t execute grep)&amp;quot;);&lt;br /&gt;
			echo &amp;quot;Can&amp;#039;t execute grep - please set the path&amp;quot;;&lt;br /&gt;
			exit;&lt;br /&gt;
		}&lt;br /&gt;
		exec(&amp;quot;$grep -hE \&amp;quot;^\s*ZM_DB_\&amp;quot; /etc/zm/zm.conf /etc/zm/conf.d/*.conf&amp;quot;, $db);&lt;br /&gt;
		foreach($db as $key =&amp;gt; $value) {&lt;br /&gt;
			unset($db[$key]);&lt;br /&gt;
			$newkey = trim(preg_replace(&amp;quot;/^\s*(ZM_DB_[^=]*)=\s*(.*)\s*$/&amp;quot;, &amp;quot;$1&amp;quot;, $value ));&lt;br /&gt;
			$newvalue = trim(preg_replace(&amp;quot;/^\s*(ZM_DB_[^=]*)=\s*(.*)\s*$/&amp;quot;, &amp;quot;$2&amp;quot;, $value ));&lt;br /&gt;
			if($newkey) {&lt;br /&gt;
				$db[$newkey] = $newvalue;&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
		unset($value);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// Got &amp;#039;em all?&lt;br /&gt;
	if( empty($db[&amp;#039;ZM_DB_HOST&amp;#039;]) || empty($db[&amp;#039;ZM_DB_NAME&amp;#039;]) || empty($db[&amp;#039;ZM_DB_USER&amp;#039;]) || empty($db[&amp;#039;ZM_DB_PASS&amp;#039;]) ) {&lt;br /&gt;
		header(&amp;quot;HTTP/1.1 500 Internal server error (database info incomplete)&amp;quot;);&lt;br /&gt;
		echo &amp;quot;Database info incomplete - Please set it manually&amp;quot;;&lt;br /&gt;
		exit;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// Connect to the database&lt;br /&gt;
	mysqli_report(MYSQLI_REPORT_OFF);&lt;br /&gt;
	if( !$dbHandle = @mysqli_connect($db[&amp;#039;ZM_DB_HOST&amp;#039;], $db[&amp;#039;ZM_DB_USER&amp;#039;], $db[&amp;#039;ZM_DB_PASS&amp;#039;], $db[&amp;#039;ZM_DB_NAME&amp;#039;]) ) {&lt;br /&gt;
		header(&amp;quot;HTTP/1.1 500 Internal server error (can&amp;#039;t connect to database)&amp;quot;);&lt;br /&gt;
		echo &amp;quot;Can&amp;#039;t connect to database: &amp;quot;.mysqli_error($dbhandle);&lt;br /&gt;
		exit;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// Query it for the file path&lt;br /&gt;
	$query = &amp;quot;SELECT CONCAT(s.`path`, &amp;#039;/&amp;#039;, e.`MonitorId`, &amp;#039;/&amp;#039;, LEFT(e.`StartDateTime`, 10), &amp;#039;/&amp;#039;, e.`Id`, &amp;#039;/&amp;#039;, e.`defaultVideo`)&lt;br /&gt;
		FROM `Events` e&lt;br /&gt;
		INNER JOIN `Storage` s&lt;br /&gt;
		ON s.`Id` = e.`StorageID`&lt;br /&gt;
		WHERE e.`id` = &amp;#039;&amp;quot;.mysqli_real_escape_string($dbHandle, $eventID).&amp;quot;&amp;#039;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
	if( !$result = @mysqli_query($dbHandle, $query) ) {&lt;br /&gt;
		header(&amp;quot;HTTP/1.1 500 Internal server error (database query failed)&amp;quot;);&lt;br /&gt;
		echo &amp;quot;Database query failed: &amp;quot;.mysqli_error($dbHandle);&lt;br /&gt;
		exit;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	// Got a result?&lt;br /&gt;
	if( (!$fullpath = @mysqli_fetch_row($result)) || empty($fullpath[0]) ) {&lt;br /&gt;
		header(&amp;quot;HTTP/1.1 500 Internal server error (empty result set or path)&amp;quot;);&lt;br /&gt;
		echo &amp;quot;Mysql returned empty result or path (bad event ID?)&amp;quot;;&lt;br /&gt;
		exit;&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
	mysqli_close($dbHandle);&lt;br /&gt;
&lt;br /&gt;
	return $fullpath[0];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
?&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Testing and Usage ===&lt;br /&gt;
&lt;br /&gt;
You can test the stream by opening it in a browser or a media player such as MPC-HC or VLC.&lt;br /&gt;
&lt;br /&gt;
If you entered a filename or an event ID in the code then you can simply visit &amp;lt;kbd&amp;gt;&amp;lt;nowiki&amp;gt;http://yourserver/replay-test.php&amp;lt;/nowiki&amp;gt;&amp;lt;/kbd&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you didn&amp;#039;t enter a filename or event ID in the code then you&amp;#039;ll need to add one to the url.&lt;br /&gt;
&lt;br /&gt;
If you&amp;#039;re using an event ID then the URL format is &amp;lt;kbd&amp;gt;&amp;lt;nowiki&amp;gt;http://yourserver/replay-test.php?e=eventID&amp;lt;/nowiki&amp;gt;&amp;lt;/kbd&amp;gt; (substituting the actual event ID for &amp;#039;eventID&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
If you want to use a file then the format is &amp;lt;kbd&amp;gt;&amp;lt;nowiki&amp;gt;http://yourserver/replay-test.php?f=/full/path/to/file.mp4&amp;lt;/nowiki&amp;gt;&amp;lt;/kbd&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the video doesn&amp;#039;t play and you&amp;#039;re using a media player then try a browser - there&amp;#039;ll probably be something useful in the output.&lt;br /&gt;
&lt;br /&gt;
If you&amp;#039;re using a browser and it just shows a black screen then the video might be H.265, which most of them don&amp;#039;t support.&lt;br /&gt;
&lt;br /&gt;
=== Setting up the monitor in ZM ===&lt;br /&gt;
&lt;br /&gt;
To use this in ZM, set up a new monitor with a Source Type of FFMpeg, a Source Path URL as described in the Testing and Usage section above, and TCP as the Method.&lt;br /&gt;
&lt;br /&gt;
That&amp;#039;s it - You should be good to go and ZM should start capturing :)&lt;br /&gt;
&lt;br /&gt;
=== Notes === &lt;br /&gt;
&lt;br /&gt;
The video is passed straight through rather than being transcoded so playback quality will be exactly as it was recorded in the file.&lt;br /&gt;
&lt;br /&gt;
The best results will probably be obtained with videos that used Camera Passthrough as the writer because then ZM will see the same thing as it did the first time - other methods will be lossy and although the differences may be imperceptible to us, machines will spot them. If you must use an encoder then try to use a low CRF, such as 19 or even 17 to avoid too much degradation.&lt;br /&gt;
&lt;br /&gt;
If you change the source video path or event ID in the PHP or if you overwrite the video file then you&amp;#039;ll have stop and restart the monitor in ZM.&lt;br /&gt;
&lt;br /&gt;
I find that the loop tends to stick at the end before restarting, but that could very well be the way my video is encoded and it may not happen to you.&lt;br /&gt;
&lt;br /&gt;
I suggest using sources with a few fairly static frames at their start end end to avoid spurious detection at the wraparound where the scene might change significantly (in ZM terms).&lt;br /&gt;
&lt;br /&gt;
Comments, questions, and criticisms are welcome in [https://forums.zoneminder.com/viewtopic.php?f=11&amp;amp;t=31355 the forum thread]&lt;br /&gt;
&lt;br /&gt;
I think that&amp;#039;s all for now - Good luck!&lt;/div&gt;</summary>
		<author><name>Kitkat</name></author>
	</entry>
	<entry>
		<id>http://wiki.staging.zoneminder.com/index.php?title=How_To&amp;diff=16742</id>
		<title>How To</title>
		<link rel="alternate" type="text/html" href="http://wiki.staging.zoneminder.com/index.php?title=How_To&amp;diff=16742"/>
		<updated>2021-12-01T04:03:28Z</updated>

		<summary type="html">&lt;p&gt;Kitkat: /* Other Stuff */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;--[[User:Stagecoach|stagecoach]] 14:11, 16 October 2010 (BST)&lt;br /&gt;
&lt;br /&gt;
Go back to the [[Contents]] page&lt;br /&gt;
&lt;br /&gt;
This section contains additional hands-on instructions to accomplish certain tasks in ZoneMinder. For the detailed documentation navigate to  the [[Main Documentation]]&lt;br /&gt;
&lt;br /&gt;
=Administration=&lt;br /&gt;
[[How to check a camera is working]]&lt;br /&gt;
&lt;br /&gt;
[[Add a user to ZoneMinder| How to add a user]]&lt;br /&gt;
&lt;br /&gt;
[[how to login| How to login]]&lt;br /&gt;
&lt;br /&gt;
[[How to enable user login]]&lt;br /&gt;
&lt;br /&gt;
[[How to change user permissions]]&lt;br /&gt;
&lt;br /&gt;
[[How to enable extra logging and debugging information]]&lt;br /&gt;
&lt;br /&gt;
=Setting up ZoneMinder Monitors=&lt;br /&gt;
[[How to setup motion detection]]&lt;br /&gt;
&lt;br /&gt;
[[How to setup motion detection#Configure motion detection areas|How to configure motion detection areas]]&lt;br /&gt;
&lt;br /&gt;
[[How to Setup an Axis211A with MPEG-4 streaming|How to setup an Axis211A with MPEG-4 streaming]]&lt;br /&gt;
&lt;br /&gt;
[[Setup axis210 with motion jpeg|How to setup an Axis210 with M-JPEG streaming]]&lt;br /&gt;
&lt;br /&gt;
[[How to Setup an Axis 210 with JPEG streaming|How to setup an Axis 210 with JPEG streaming]]&lt;br /&gt;
&lt;br /&gt;
[[How to setup an axis 213 with pan tilt zoom|How to setup an Axis213 with pan tilt zoom]]&lt;br /&gt;
&lt;br /&gt;
[[How to setup a File monitor]]&lt;br /&gt;
&lt;br /&gt;
[[How to setup LibVLC on a camera]]&lt;br /&gt;
&lt;br /&gt;
[[How to setup MPEG-4 (part 2) streaming with RTP/RTSP monitor from an Axis 225FD camera]]&lt;br /&gt;
&lt;br /&gt;
[[How to setup MPEG-4 (part 2) streaming with RTP/RTSP monitor from an Axis 241S video encoder]]&lt;br /&gt;
&lt;br /&gt;
[[How to setup MPEG-4 streaming with RTSP monitor from a Vivotek IP8332 camera]]&lt;br /&gt;
&lt;br /&gt;
[[How to setup H.264 streaming with Ffmpeg monitor from an Axis P3343-VE-12mm camera]]&lt;br /&gt;
&lt;br /&gt;
[[How to setup H.264 streaming with Ffmpeg monitor from an Axis M7001 video encoder]]&lt;br /&gt;
&lt;br /&gt;
[[How to setup H.264 streaming with Ffmpeg monitor from an MagicWave Systems License Plate Camera]]&lt;br /&gt;
&lt;br /&gt;
[[How to Setup a FLIR F-Series Thermal Camera with MPEG4 streaming]]&lt;br /&gt;
&lt;br /&gt;
[[How to share an USB camera from a remote ZM server to another ZM Server]]&lt;br /&gt;
&lt;br /&gt;
=Exporting Events=&lt;br /&gt;
[[How to export download and view events#Export_Methods| How to export and download events]]&lt;br /&gt;
&lt;br /&gt;
[[How to export download and view events#Extracting_Events|How to prepare exported events for playback]]&lt;br /&gt;
&lt;br /&gt;
[[How to export download and view events#Viewing_Extracted_Events|How to view extracted events]]&lt;br /&gt;
&lt;br /&gt;
[[How_to_export_an_event_as_video|How to export an event as video]]&lt;br /&gt;
&lt;br /&gt;
=Live streaming=&lt;br /&gt;
[[How to realtime view multiple cameras]]&lt;br /&gt;
&lt;br /&gt;
[[How_to_get_a_live_view_from_a_monitor##Watch_view|How to get a live view from a single monitor]]&lt;br /&gt;
&lt;br /&gt;
[[How_to_get_a_live_view_from_a_monitor##cycle_view|How to get a rotating view from a group of monitors]]&lt;br /&gt;
&lt;br /&gt;
[[How to realtime view multiple cameras#Change Montage View|How to change the montage views layout]]&lt;br /&gt;
&lt;br /&gt;
[[How to realtime view multiple cameras#Create new group|How to create a new camera group]]&lt;br /&gt;
&lt;br /&gt;
[[How to stream from another ZoneMinder installation]]&lt;br /&gt;
&lt;br /&gt;
[[How to view recorded history from show timeline]]&lt;br /&gt;
&lt;br /&gt;
=Other Stuff=&lt;br /&gt;
[[How to stream h264 with ffmpeg from an Axis P3343]]&lt;br /&gt;
&lt;br /&gt;
[[Capture Resolution Width x Height]]&lt;br /&gt;
&lt;br /&gt;
[[How to install and configure Postfix as a Gmail SMTP relay for ZoneMinder email filter events.]]&lt;br /&gt;
&lt;br /&gt;
[[How to use a video file as a Source]]&lt;/div&gt;</summary>
		<author><name>Kitkat</name></author>
	</entry>
	<entry>
		<id>http://wiki.staging.zoneminder.com/index.php?title=How_to_use_a_video_file_as_a_Source&amp;diff=16741</id>
		<title>How to use a video file as a Source</title>
		<link rel="alternate" type="text/html" href="http://wiki.staging.zoneminder.com/index.php?title=How_to_use_a_video_file_as_a_Source&amp;diff=16741"/>
		<updated>2021-12-01T04:01:53Z</updated>

		<summary type="html">&lt;p&gt;Kitkat: Created page with &amp;quot;There was [https://forums.zoneminder.com/viewtopic.php?f=43&amp;amp;t=31176 a question on the forums] a while ago asking whether it was possible to test zones against stored events, w...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;There was [https://forums.zoneminder.com/viewtopic.php?f=43&amp;amp;t=31176 a question on the forums] a while ago asking whether it was possible to test zones against stored events, which interested me, and I&amp;#039;ve cobbled together a fairly reliable method of doing it with PHP and FFMpeg.&lt;br /&gt;
&lt;br /&gt;
=== Code ===&lt;br /&gt;
&lt;br /&gt;
Create a file named &amp;lt;kbd&amp;gt;replay-test.php&amp;lt;/kbd&amp;gt; in your server&amp;#039;s web root (not the ZM root), paste this into it, fixing the source video and ffmpeg paths to suit your installation, and save it. On CentOS the web root is &amp;lt;kbd&amp;gt;/var/www/html&amp;lt;/kbd&amp;gt; so you&amp;#039;d do something like, &amp;lt;kbd&amp;gt;sudo nano /var/www/html/replay-test.php&amp;lt;/kbd&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?PHP&lt;br /&gt;
&lt;br /&gt;
// Change this to point to your source video file&lt;br /&gt;
$infile = &amp;quot;/home/zoneminder/events/1/2021-11-30/173016/173016-video.mp4&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// Whether to loop the video&lt;br /&gt;
// Use -1 for infinite,&lt;br /&gt;
// 0 for single-shot,&lt;br /&gt;
// 1 for 1 loop (two &amp;#039;plays&amp;#039;), etc.&lt;br /&gt;
// Anything other than -1 will throw errors in the ZM log as&lt;br /&gt;
// it fails to capture and restarts the zmc process&lt;br /&gt;
$loopcount = -1;&lt;br /&gt;
&lt;br /&gt;
// Path to ffpmeg - try &amp;#039;which ffmpeg&amp;#039; at the CLI to find yours&lt;br /&gt;
$ffmpeg = &amp;quot;/usr/bin/ffmpeg&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// No variables defined below here&lt;br /&gt;
&lt;br /&gt;
// Got a filename as a parameter?&lt;br /&gt;
if( !empty($_GET[&amp;#039;f&amp;#039;]) ) {&lt;br /&gt;
		$infile = $_GET[&amp;#039;f&amp;#039;];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Can we read the file?&lt;br /&gt;
if( !is_readable($infile) ) {&lt;br /&gt;
		header(&amp;quot;HTTP/1.1 500 Internal Server Error (can&amp;#039;t read $f)&amp;quot;);&lt;br /&gt;
		exit;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Don&amp;#039;t allow max_execution_time to kill us&lt;br /&gt;
set_time_limit(0);&lt;br /&gt;
&lt;br /&gt;
// Tell the client what we&amp;#039;re sending&lt;br /&gt;
header( &amp;quot;Content-Type: video/mp4&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
// Send it...&lt;br /&gt;
passthru( $ffmpeg.&amp;quot; -stream_loop &amp;quot;.$loopcount.&amp;quot; -re -i &amp;#039;&amp;quot;.$infile.&amp;quot;&amp;#039; -vcodec copy -an -vsync 0 -f mp4 -movflags frag_keyframe+empty_moov - 2&amp;gt;/dev/null&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Testing ===&lt;br /&gt;
&lt;br /&gt;
You can test the stream by opening it in a browser or media player such as MPC-HC or VLC: &amp;lt;kbd&amp;gt;&amp;lt;nowiki&amp;gt;http://ip.add.re.ss/replay-test.php&amp;lt;/nowiki&amp;gt;&amp;lt;/kbd&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Setting up the monitor in ZM ===&lt;br /&gt;
&lt;br /&gt;
Set up a new monitor in ZM with a Source Type of FFMpeg, a Source Path of &amp;lt;kbd&amp;gt;&amp;lt;nowiki&amp;gt;http://localhost/replay-test.php&amp;lt;/nowiki&amp;gt;&amp;lt;/kbd&amp;gt;, and TCP as the Method.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
That&amp;#039;s it - You should be good to go and ZM should start capturing :)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Notes === &lt;br /&gt;
&lt;br /&gt;
The video is passed straight through rather than being transcoded so playback quality will be exactly as it was recorded in the file.&lt;br /&gt;
&lt;br /&gt;
The best results will probably be obtained with videos that used Camera Passthrough as the writer because then ZM will see the same thing as it did the first time - other methods will be lossy and although the differences may be imperceptible to us, machines will spot them. If you must use an encoder then try to use a low CRF, such as 19 or even 17 to avoid too much degradation.&lt;br /&gt;
&lt;br /&gt;
You can change the file to be replayed without editing the PHP by adding a &amp;lt;kbd&amp;gt;?f=/path/to/file.mp4&amp;lt;/kbd&amp;gt; query string to the Source Path in the Monitor configuration (e.g. &amp;lt;kbd&amp;gt;&amp;lt;nowiki&amp;gt;http://localhost/replay-test.php?f=/home/zoneminder/events/1/2021-11-30/173016/173016-video.mp4&amp;lt;/nowiki&amp;gt;&amp;lt;/kbd&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
If you change the source video path in the PHP or if you overwrite the video file then you&amp;#039;ll have stop and restart the monitor in ZM.&lt;br /&gt;
&lt;br /&gt;
I find that the loop tends to stick at the end before restarting, but that could very well be the way my video is encoded and it may not happen to you.&lt;br /&gt;
&lt;br /&gt;
I suggest using sources with fairly long (a few frames or so) intros and outros without much happening in them to avoid spurious detection at the wraparound where the scene might change significantly (in ZM terms).&lt;br /&gt;
&lt;br /&gt;
Comments, criticisms, and questions are welcome in [https://forums.zoneminder.com/viewtopic.php?f=11&amp;amp;t=31355 the forum thread]&lt;br /&gt;
&lt;br /&gt;
I think that&amp;#039;s all for now - Good luck!&lt;/div&gt;</summary>
		<author><name>Kitkat</name></author>
	</entry>
</feed>