128128 word-break : break-all;
129129 user-select : all;
130130 cursor : text;
131+ margin-bottom : 20px ;
131132}
132133
133134.info {
@@ -167,10 +168,12 @@ <h1>FFmpeg video crop</h1>
167168 < div class ="command-container hidden " id ="commandContainer ">
168169 < div class ="command-label "> FFmpeg command:</ div >
169170 < div class ="command " id ="ffmpegCommand "> </ div >
171+ < div class ="command-label "> Recommended settings for iPhone compatibility:</ div >
172+ < div class ="command " id ="ffmpegCommandIOS "> </ div >
170173 </ div >
171174
172175 < div class ="info ">
173- Upload a video file, then drag the green crop box to select the area you want to keep. The ffmpeg command will update automatically as you adjust the crop area.
176+ Upload a video file, then drag the green crop box to select the area you want to keep. The ffmpeg commands will update automatically as you adjust the crop area.
174177 </ div >
175178
176179 < script type ="module ">
@@ -182,6 +185,7 @@ <h1>FFmpeg video crop</h1>
182185const cropDimensions = document . getElementById ( 'cropDimensions' ) ;
183186const commandContainer = document . getElementById ( 'commandContainer' ) ;
184187const ffmpegCommand = document . getElementById ( 'ffmpegCommand' ) ;
188+ const ffmpegCommandIOS = document . getElementById ( 'ffmpegCommandIOS' ) ;
185189
186190let videoWidth = 0 ;
187191let videoHeight = 0 ;
@@ -198,23 +202,22 @@ <h1>FFmpeg video crop</h1>
198202// Initialize crop box position and size
199203function initializeCropBox ( ) {
200204 const rect = video . getBoundingClientRect ( ) ;
201- const overlayRect = cropOverlay . getBoundingClientRect ( ) ;
202205
203206 // Set initial crop box to 50% of video size, centered
204207 const initialWidth = rect . width * 0.5 ;
205208 const initialHeight = rect . height * 0.5 ;
206209 const initialLeft = ( rect . width - initialWidth ) / 2 ;
207210 const initialTop = ( rect . height - initialHeight ) / 2 ;
208211
209- cropBox . style . left = initialLeft + 'px' ;
210- cropBox . style . top = initialTop + 'px' ;
211- cropBox . style . width = initialWidth + 'px' ;
212- cropBox . style . height = initialHeight + 'px' ;
212+ cropBox . style . left = ` ${ initialLeft } px` ;
213+ cropBox . style . top = ` ${ initialTop } px` ;
214+ cropBox . style . width = ` ${ initialWidth } px` ;
215+ cropBox . style . height = ` ${ initialHeight } px` ;
213216
214217 updateCommand ( ) ;
215218}
216219
217- // Update ffmpeg command based on crop box
220+ // Update ffmpeg commands based on crop box
218221function updateCommand ( ) {
219222 const rect = video . getBoundingClientRect ( ) ;
220223 const boxRect = cropBox . getBoundingClientRect ( ) ;
@@ -232,11 +235,17 @@ <h1>FFmpeg video crop</h1>
232235 // Update dimensions display
233236 cropDimensions . textContent = `${ cropW } × ${ cropH } ` ;
234237
235- // Update ffmpeg command
238+ // Build file names
236239 const inputFile = videoInput . files [ 0 ] ? videoInput . files [ 0 ] . name : 'input.mp4' ;
237- const outputFile = inputFile . replace ( / \. [ ^ / . ] + $ / , '' ) + '_cropped.mp4' ;
240+ const baseName = inputFile . replace ( / \. [ ^ / . ] + $ / , '' ) ;
241+ const outputFile = `${ baseName } _cropped.mp4` ;
242+ const outputFileIOS = `${ baseName } _cropped_ios.mp4` ;
238243
244+ // Standard command
239245 ffmpegCommand . textContent = `ffmpeg -i "${ inputFile } " -vf "crop=${ cropW } :${ cropH } :${ cropX } :${ cropY } " -c:a copy "${ outputFile } "` ;
246+
247+ // iPhone‑friendly command
248+ ffmpegCommandIOS . textContent = `ffmpeg -i "${ inputFile } " -vf "crop=${ cropW } :${ cropH } :${ cropX } :${ cropY } " -c:v libx264 -profile:v main -level 3.1 -pix_fmt yuv420p -c:a copy "${ outputFileIOS } "` ;
240249}
241250
242251// Handle video file selection
@@ -254,10 +263,8 @@ <h1>FFmpeg video crop</h1>
254263 commandContainer . classList . remove ( 'hidden' ) ;
255264
256265 // Wait for next frame to ensure video is rendered
257- requestAnimationFrame ( ( ) => {
258- initializeCropBox ( ) ;
259- } ) ;
260- } ) ;
266+ requestAnimationFrame ( initializeCropBox ) ;
267+ } , { once : true } ) ;
261268 }
262269} ) ;
263270
@@ -310,8 +317,8 @@ <h1>FFmpeg video crop</h1>
310317 newLeft = Math . max ( 0 , Math . min ( newLeft , maxLeft ) ) ;
311318 newTop = Math . max ( 0 , Math . min ( newTop , maxTop ) ) ;
312319
313- cropBox . style . left = newLeft + 'px' ;
314- cropBox . style . top = newTop + 'px' ;
320+ cropBox . style . left = ` ${ newLeft } px` ;
321+ cropBox . style . top = ` ${ newTop } px` ;
315322
316323 updateCommand ( ) ;
317324 }
@@ -346,15 +353,15 @@ <h1>FFmpeg video crop</h1>
346353 // Minimum size constraints
347354 if ( newWidth >= 50 && newHeight >= 50 ) {
348355 // Constrain to video bounds
349- if ( newLeft >= 0 && newTop >= 0 &&
350- newLeft + newWidth <= cropOverlay . offsetWidth &&
351- newTop + newHeight <= cropOverlay . offsetHeight ) {
352-
353- cropBox . style . left = newLeft + 'px' ;
354- cropBox . style . top = newTop + 'px' ;
355- cropBox . style . width = newWidth + 'px' ;
356- cropBox . style . height = newHeight + 'px' ;
357-
356+ if (
357+ newLeft >= 0 && newTop >= 0 &&
358+ newLeft + newWidth <= cropOverlay . offsetWidth &&
359+ newTop + newHeight <= cropOverlay . offsetHeight
360+ ) {
361+ cropBox . style . left = ` ${ newLeft } px` ;
362+ cropBox . style . top = ` ${ newTop } px` ;
363+ cropBox . style . width = ` ${ newWidth } px` ;
364+ cropBox . style . height = ` ${ newHeight } px` ;
358365 updateCommand ( ) ;
359366 }
360367 }
0 commit comments