Video dominates social media feeds, and the demand keeps on growing. Between 2022 and 2023, a survey from SocialInsider revealed Instagram Reels had a year-over-year growth rate of 57.4%. From user-generated content (UGC) to paid ads, our social media feeds are full of video content.
Turn your long-form videos into digestible clips that fit the format requirements of these platforms with Next.js and Cloudinary. This blog post will teach you how to build a video snipping tool with Next.js, using Cloudinary’s trim and resize features to easily customize your videos.
Before we start, you should have a basic understanding of TypeScript or JavaScript and a free Cloudinary account. You can also find the complete code implementation in this GitHub repository.
To set up the Next.js project, clone the starter project. This starter project contains the styles for the app so you can focus on building the core functionality. Clone the repo using the command below:
<code>git clone https://github.com/folucode/video-snipping-tool-starter.git </code>
Code language: HTML, XML (xml)
Next, install the Cloudinary packages in the project directory using the command below. The @cloudinary/react
package provides React components that make it easy to work directly with Cloudinary’s media features in your React or NextJS project. In contrast, the @cloudinary/url-gen
package allows you to dynamically generate URLs for images and videos with transformations using Cloudinary’s API.
<code>npm install @cloudinary/react @cloudinary/url-gen</code>
Code language: HTML, XML (xml)
Then, run npm run dev
to render a development server at https://localhost:3000/ in your browser.
In the project’s root directory, add a new file, .env.local, and paste the code below in that file. This file will contain your Cloudinary cloud name. Your cloud name is what you will use to access your Cloudinary account programatically.
<code>NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME=<CLOUDINARY_CLOUD_NAME></code>
Code language: HTML, XML (xml)
To get your cloud name, navigate to the Cloudinary developer dashboard. You should see it under the Product Environment Credentials section, as shown in the image below:
After adding your cloud name to the .env.local
file, in the following section you will build the core functionality of the app.
Before you proceed, you need to upload a video to your Cloudinary account. Check here to learn how to upload a video to Cloudinary.
Next, in the page.tsx
file, you must first set up the Cloudinary instance object and the video you want to transform. To do this, create a Cloudinary object using the public environment variable for the cloudName
. This object will allow you to perform the transformations and load the video.
// src/page.tsx
// ...
import { Cloudinary } from '@cloudinary/url-gen';
const cloudName = process.env.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME;
const cloudinary: Cloudinary = new Cloudinary({
cloud: {
cloudName,
},
});
const videoId: string = 'video-public-id';
export default function Home() {
// ...
}
Code language: JavaScript (javascript)
The videoId
in the code above is the relative path to the video on your Cloudinary account without the file extension. For this example video, the videoId
will be docs/walking_talking
.
In the next section, you’ll set up the form inputs and corresponding state variables to capture user input for the start time, end time, and aspect ratio. This will allow you to control which section of the video to edit and specify the video’s format for different platforms.
To set up the form and state variables, you can use React’s useState hook to dynamically manage and update these values as you interact with the form. See the code snippet below:
// src/page.tsx
// ...
import { useState } from 'react';
...
export default function Home() {
const [startTime, setStartTime] = useState(0);
const [endTime, setEndTime] = useState(0);
const [aspectRatio, setAspectRatio] = useState('');
// Add form inputs for start time, end time, and aspect ratio
return (
<div className={styles.main}>
<h1>Video Snipping Tool</h1>
<div className={styles.grid}>
<div>
<label>
Start Time (seconds):
<input
className={styles.input}
type='number'
value={startTime}
onChange={(e) => setStartTime(Number(e.target.value))}
/>
</label>
<label>
End Time (seconds):
<input
className={styles.input}
type='number'
value={endTime}
onChange={(e) => setEndTime(Number(e.target.value))}
/>
</label>
<label>Platform: </label>
<select
value={aspectRatio}
className={styles.input}
onChange={(e) => setAspectRatio(e.target.value)}
>
<option value='9:16'>Instagram Reels</option>
<option value='1:1'>Instagram Feed</option>
<option value='16:9'>YouTube Standard</option>
</select>
</div>
</div>
</div>
);
Code language: JavaScript (javascript)
In the code block above, you set up state variables to capture user input for the start time, end time, and aspect ratio. Then, you created form inputs to allow users to modify these values dynamically.
Finally, to implement the functionality to transform the video and display a preview, transformations, such as resizing and trimming, must be applied based on the start time, end time, and aspect ratio values provided.
Once the transformations are applied, you can use Cloudinary’s advanced video component to render a preview of the transformed video, allowing users to see the changes on the fly.
// src/page.tsx
...
import { fill } from '@cloudinary/url-gen/actions/resize';
import { trim } from '@cloudinary/url-gen/actions/videoEdit';
import { AdvancedVideo } from '@cloudinary/react';
...
export default function Home() {
...
const [transformedVideo, setTransformedVideo] = useState(
new CloudinaryVideo(videoId, { cloudName })
);
// Function to transform the video
const getTransformedVideo = (): void => {
if (endTime <= startTime) {
alert('End time must be greater than start time.');
return;
}
const adjustedStartTime = Math.max(0, startTime);
const adjustedEndTime = endTime + 1;
const videoTransformation = cloudinary
.video(videoId)
.resize(fill().aspectRatio(aspectRatio).gravity('center'))
.videoEdit(
trim().startOffset(adjustedStartTime).endOffset(adjustedEndTime)
);
setTransformedVideo(videoTransformation);
};
return (
<div className={styles.main}>
<h1>Video Snipping Tool</h1>
<div className={styles.grid}>
<div>
{/* Form inputs for video transformation (startTime, endTime, aspectRatio) */}
<button className={styles.button} onClick={getTransformedVideo}>
Transform
</button>
</div>
<div className={styles.videoContainer}>
<h3>Preview:</h3>
{transformedVideo && (
<AdvancedVideo cldVid={transformedVideo} controls />
)}
</div>
</div>
</div>
);
}
Code language: JavaScript (javascript)
In this code block, you set up a function to apply video transformations based on your defined start time, end time, and aspect ratio. The start and end times are adjusted to ensure that the selected video segment provides a smoother playback experience. The adjusted start time is set to a minimum of zero. In contrast, the adjusted end time is extended by one second to include additional footage beyond the selected endpoint. This approach results in a more polished final video.
The transformation process involves applying resizing and trimming actions using the Cloudinary SDK. Here’s a breakdown:
cloudinary.video(videoId)
. This initiates a video transformation using Cloudinary. ThevideoId
is the unique identifier of the video in Cloudinary’s storage, and.video(videoId)
prepares it for transformations..resize(fill().aspectRatio(aspectRatio).gravity('center')).
This resizes the video:fill().
` This resizing mode scales the video to fill the specified dimensions, cropping it as needed to ensure it completely fills the frame..aspectRatio(aspectRatio).
Sets the aspect ratio, which could be something like 16:9 or 1:1. It ensures the video dimensions maintain this ratio..gravity('center').
Ensures that any cropping happens centrally, so the main part of the video stays in the frame.
.videoEdit(trim().startOffset(adjustedStartTime).endOffset(adjustedEndTime)).
This trims the video:trim().
Starts the trimming process, allowing you to specify start and end times..startOffset(adjustedStartTime).
Sets the start time for the trim (in seconds)..endOffset(adjustedEndTime).
Sets the end time for the trim.
After the transformation process, the preview initially shows the video without any transformation applied, allowing you to see the original content before applying your edits. After the transformations are applied, the transformedVideo
state variable is updated, and the preview reflects the changes, enabling you to review your edits in real time.
To see these steps in action, watch this demo showing the automatic transformation of a video hosted on Cloudinary.
In this blog post, you learned how to implement a video snipping tool using Cloudinary. This tool allows you to resize and trim videos based on user-defined parameters. You can enhance this application by adding features such as the ability for users to upload their videos directly, implementing validation for user inputs to ensure better usability, or integrating additional transformation options like filters and effects. Contact us today to learn more about how Cloudinary can help improve your app’s user experience.
If you found this blog post helpful and want to discuss it more, join the Cloudinary Community forum and its associated Discord.