Skip to content

Instantly share code, notes, and snippets.

@elbruno
Created February 2, 2026 16:17
Show Gist options
  • Select an option

  • Save elbruno/48e94f07c7026b82f3796fc718b349f3 to your computer and use it in GitHub Desktop.

Select an option

Save elbruno/48e94f07c7026b82f3796fc718b349f3 to your computer and use it in GitHub Desktop.
#!/usr/bin/env dotnet run
#:package OpenCvSharp4@4.*
#:package OpenCvSharp4.runtime.win@4.*
/*
Video Extension Tool (.NET 10)
Extends a video by adding extra time using the last frame.
Usage: dotnet run extendvideo.cs
Demo for El Bruno's YouTube channel: https://www.youtube.com/elbruno
*/
using OpenCvSharp;
// Supported video extensions
string[] videoExtensions = [".mp4", ".avi", ".mov", ".mkv", ".wmv", ".flv"];
Console.WriteLine(new string('=', 50));
Console.WriteLine(" 🎥 Video Extension Tool (.NET)");
Console.WriteLine(new string('=', 50));
// Get videos from current folder
var videos = GetVideosFromFolder();
if (videos.Count == 0)
{
Console.WriteLine("\n❌ No video files found in the current folder.");
Console.WriteLine(" Supported formats: mp4, avi, mov, mkv, wmv, flv");
return;
}
// Select video
var selectedVideo = SelectVideo(videos);
Console.WriteLine($"\n✅ Selected: {Path.GetFileName(selectedVideo)}");
// Select extra time
var extraTime = SelectExtraTime();
Console.WriteLine($"✅ Extra time: {extraTime} seconds");
// Extend the video
try
{
var (outputPath, originalDuration, newDuration) = ExtendVideo(selectedVideo, extraTime);
// Show results
Console.WriteLine("\n" + new string('=', 50));
Console.WriteLine(" 📊 Results");
Console.WriteLine(new string('=', 50));
Console.WriteLine($" Original duration: {FormatDuration(originalDuration)}");
Console.WriteLine($" New duration: {FormatDuration(newDuration)}");
Console.WriteLine($" New video: {Path.GetFileName(outputPath)}");
Console.WriteLine(new string('=', 50));
Console.WriteLine("\n✅ Video extended successfully!");
}
catch (Exception ex)
{
Console.WriteLine($"\n❌ Error processing video: {ex.Message}");
}
// --- Functions ---
List<string> GetVideosFromFolder(string folder = ".")
{
var videos = new List<string>();
foreach (var ext in videoExtensions)
{
videos.AddRange(Directory.GetFiles(folder, $"*{ext}", SearchOption.TopDirectoryOnly));
}
return videos.Take(5).ToList();
}
string SelectVideo(List<string> videoList)
{
Console.WriteLine("\n📹 Available videos:");
for (int i = 0; i < videoList.Count; i++)
{
var defaultLabel = i == 0 ? " (default)" : "";
Console.WriteLine($" {i + 1}. {Path.GetFileName(videoList[i])}{defaultLabel}");
}
Console.Write("\nSelect a video [1]: ");
var choice = Console.ReadLine()?.Trim() ?? "";
if (string.IsNullOrEmpty(choice) || !int.TryParse(choice, out int idx))
return videoList[0];
idx--;
return (idx >= 0 && idx < videoList.Count) ? videoList[idx] : videoList[0];
}
int SelectExtraTime()
{
int[] options = [5, 10, 15];
Console.WriteLine("\n⏱️ Select extra time (seconds):");
for (int i = 0; i < options.Length; i++)
{
var defaultLabel = options[i] == 5 ? " (default)" : "";
Console.WriteLine($" {i + 1}. {options[i]} seconds{defaultLabel}");
}
Console.Write("\nSelect extra time [1]: ");
var choice = Console.ReadLine()?.Trim() ?? "";
if (string.IsNullOrEmpty(choice) || !int.TryParse(choice, out int idx))
return 5;
idx--;
return (idx >= 0 && idx < options.Length) ? options[idx] : 5;
}
(string outputPath, double originalDuration, double newDuration) ExtendVideo(string videoPath, int extraSeconds)
{
Console.WriteLine($"\n🎬 Processing: {Path.GetFileName(videoPath)}");
// Open the video
using var cap = new VideoCapture(videoPath);
if (!cap.IsOpened())
throw new Exception($"Cannot open video: {videoPath}");
// Get video properties
var fps = cap.Fps;
var width = (int)cap.Get(VideoCaptureProperties.FrameWidth);
var height = (int)cap.Get(VideoCaptureProperties.FrameHeight);
var totalFrames = (int)cap.Get(VideoCaptureProperties.FrameCount);
var originalDuration = totalFrames / fps;
// Generate output filename
var directory = Path.GetDirectoryName(videoPath) ?? ".";
var baseName = Path.GetFileNameWithoutExtension(videoPath);
var ext = Path.GetExtension(videoPath);
var outputPath = Path.Combine(directory, $"{baseName}_extended{ext}");
// Set up video writer
var fourcc = FourCC.MP4V;
using var writer = new VideoWriter(outputPath, fourcc, fps, new Size(width, height));
Console.WriteLine("📝 Writing extended video...");
using var lastFrame = new Mat();
var frameCount = 0;
// Copy all original frames
using var frame = new Mat();
while (true)
{
if (!cap.Read(frame) || frame.Empty())
break;
frame.CopyTo(lastFrame);
writer.Write(frame);
frameCount++;
if (frameCount % 100 == 0)
Console.Write($"\r Processed {frameCount}/{totalFrames} frames...");
}
Console.WriteLine($"\r Processed {frameCount}/{totalFrames} frames... ");
// Add extra frames using the last frame
var extraFrames = (int)(extraSeconds * fps);
Console.WriteLine($" Adding {extraFrames} extra frames ({extraSeconds}s)...");
for (int i = 0; i < extraFrames; i++)
{
writer.Write(lastFrame);
if ((i + 1) % 100 == 0)
Console.Write($"\r Added {i + 1}/{extraFrames} extra frames...");
}
Console.WriteLine($"\r Added {extraFrames}/{extraFrames} extra frames... ");
var newDuration = originalDuration + extraSeconds;
return (outputPath, originalDuration, newDuration);
}
string FormatDuration(double seconds)
{
var minutes = (int)(seconds / 60);
var secs = (int)(seconds % 60);
return $"{minutes:D2}:{secs:D2}";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment