@@ -42,6 +42,26 @@ public function isAvailable(FileInfo $file): bool {
4242		return  is_string ($ this binary );
4343	}
4444
45+ 	private  function  connectDirect (File $ filestring |false  {
46+ 		if  (stream_get_meta_data ($ filefopen ('r ' ))['seekable ' ] !== true ) {
47+ 			return  false ;
48+ 		}
49+ 
50+ 		// Checks for availability to access the video file directly via HTTP/HTTPS. 
51+ 		// Returns a string containing URL if available. Only implemented and tested 
52+ 		// with Amazon S3 currently.  In all other cases, return false. ffmpeg 
53+ 		// supports other protocols so this function may expand in the future. 
54+ 		$ gddValues$ filegetStorage ()->getDirectDownload ($ filegetName ());
55+ 
56+ 		if  (is_array ($ gddValues
57+ 			if  (array_key_exists ('url ' , $ gddValuesarray_key_exists ('presigned ' , $ gddValues
58+ 				$ directUrlstr_starts_with ($ gddValues'url ' ], 'http ' ) && ($ gddValues'presigned ' ] === true )) ? $ gddValues'url ' ] : false ;
59+ 				return  $ directUrl
60+ 			}
61+ 		}
62+ 		return  false ;
63+ 	}
64+ 
4565	/** 
4666	 * {@inheritDoc} 
4767	 */ 
@@ -54,58 +74,72 @@ public function getThumbnail(File $file, int $maxX, int $maxY): ?IImage {
5474
5575		$ resultnull ;
5676
77+ 		$ connectDirect$ this connectDirect ($ file
78+ 
5779		// Timestamps to make attempts to generate a still 
5880		$ timeAttempts5 , 1 , 0 ];
5981
60- 		// By default, download $sizeAttempts from the file along with 
61- 		// the 'moov' atom. 
62- 		// Example bitrates in the higher range: 
63- 		// 4K HDR H265 60 FPS = 75 Mbps = 9 MB per second needed for a still 
64- 		// 1080p H265 30 FPS = 10 Mbps = 1.25 MB per second needed for a still 
65- 		// 1080p H264 30 FPS = 16 Mbps = 2 MB per second needed for a still 
66- 		$ sizeAttempts1024  * 1024  * 10 ];
67- 
68- 		if  ($ this useTempFile ($ file
69- 			if  ($ filegetStorage ()->isLocal ()) {
70- 				// Temp file required but file is local, so retrieve $sizeAttempt bytes first, 
71- 				// and if it doesn't work, retrieve the entire file. 
72- 				$ sizeAttemptsnull ;
82+ 		// If HTTP/HTTPS direct connect is not available or if the file is encrypted, 
83+ 		// process normally 
84+ 		if  (($ connectDirectfalse ) || $ fileisEncrypted ()) {
85+ 			// By default, download $sizeAttempts from the file along with 
86+ 			// the 'moov' atom. 
87+ 			// Example bitrates in the higher range: 
88+ 			// 4K HDR H265 60 FPS = 75 Mbps = 9 MB per second needed for a still 
89+ 			// 1080p H265 30 FPS = 10 Mbps = 1.25 MB per second needed for a still 
90+ 			// 1080p H264 30 FPS = 16 Mbps = 2 MB per second needed for a still 
91+ 			$ sizeAttempts1024  * 1024  * 10 ];
92+ 
93+ 			if  ($ this useTempFile ($ file
94+ 				if  ($ filegetStorage ()->isLocal ()) {
95+ 					// Temp file required but file is local, so retrieve $sizeAttempt bytes first, 
96+ 					// and if it doesn't work, retrieve the entire file. 
97+ 					$ sizeAttemptsnull ;
98+ 				}
99+ 			} else  {
100+ 				// Temp file is not required and file is local so retrieve entire file. 
101+ 				$ sizeAttemptsnull ];
73102			}
74- 		} else  {
75- 			// Temp file is not required and file is local so retrieve entire file. 
76- 			$ sizeAttemptsnull ];
77- 		}
78103
79- 		foreach  ($ sizeAttemptsas  $ size
80- 			$ absPathfalse ;
81- 			// File is remote, generate a sparse file 
82- 			if  (!$ filegetStorage ()->isLocal ()) {
83- 				$ absPath$ this getSparseFile ($ file$ size
84- 			}
85- 			// Defaults to existing routine if generating sparse file fails 
86- 			if  ($ absPathfalse ) {
87- 				$ absPath$ this getLocalFile ($ file$ size
88- 			}
89- 			if  ($ absPathfalse ) {
90- 				Server::get (LoggerInterface::class)->error (
91- 					'Failed to get local file to generate thumbnail for:  '  . $ filegetPath (),
92- 					['app '  => 'core ' ]
93- 				);
94- 				return  null ;
95- 			}
104+ 			foreach  ($ sizeAttemptsas  $ size
105+ 				$ absPathfalse ;
106+ 				// File is remote, generate a sparse file 
107+ 				if  (!$ filegetStorage ()->isLocal ()) {
108+ 					$ absPath$ this getSparseFile ($ file$ size
109+ 				}
110+ 				// Defaults to existing routine if generating sparse file fails 
111+ 				if  ($ absPathfalse ) {
112+ 					$ absPath$ this getLocalFile ($ file$ size
113+ 				}
114+ 				if  ($ absPathfalse ) {
115+ 					Server::get (LoggerInterface::class)->error (
116+ 						'Failed to get local file to generate thumbnail for:  '  . $ filegetPath (),
117+ 						['app '  => 'core ' ]
118+ 					);
119+ 					return  null ;
120+ 				}
121+ 
122+ 				// Attempt still image grabs from selected timestamps 
123+ 				foreach  ($ timeAttemptsas  $ timeStamp
124+ 					$ result$ this generateThumbNail ($ maxX$ maxY$ absPath$ timeStamp
125+ 					if  ($ resultnull ) {
126+ 						break ;
127+ 					}
128+ 				}
129+ 
130+ 				$ this cleanTmpFiles ();
96131
97- 			// Attempt still image grabs from selected timestamps 
98- 			foreach  ($ timeAttemptsas  $ timeStamp
99- 				$ result$ this generateThumbNail ($ maxX$ maxY$ absPath$ timeStamp
100132				if  ($ resultnull ) {
101133					break ;
102134				}
103135			}
104- 
105- 			$ this cleanTmpFiles ();
106- 
107- 			if  ($ resultnull ) {
108- 				break ;
136+ 		} else  {
137+ 			// HTTP/HTTPS direct connect is available so pass the URL directly to ffmpeg 
138+ 			foreach  ($ timeAttemptsas  $ timeStamp
139+ 				$ result$ this generateThumbNail ($ maxX$ maxY$ connectDirect$ timeStamp
140+ 				if  ($ resultnull ) {
141+ 					break ;
142+ 				}
109143			}
110144		}
111145		return  $ result
0 commit comments