压缩我的视频





5.00/5 (3投票s)
一个非常简单的程序,用于就地压缩视频。
介绍
下面的代码片段压缩了我的个人视频。
背景
我的家用硬盘上有大量的个人视频。不幸的是,这些视频直接来自照相机,压缩率很低。
首先,我使用一个程序来删除重复文件:http://www.nirsoft.net/utils/search_my_files.html
然后,我尝试了一些工具来压缩它们。我找到的最佳工具是 winff。
不幸的是,它需要一个输出文件夹,并且不允许我在视频所在的文件夹中直接压缩它们。它也不能压缩文件路径中包含重音字母的文件。
当你有几百个视频时,这就会成为一个真正的问题。
使用代码
然后,由于我找不到一个可以就地压缩文件的工具,我编写了下面的程序。
虽然这个程序对我有效,但它是针对我自己的问题定制的,可能需要修改才能适用于你的场景。
using System;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
namespace CompressVideos
{
class Program
{
// 20,875 files / 538 folders
// 57.0 GB (61,256,840,351 bytes)
const string FFMPEG_SUFFIX = "(ffmpeg)";
private static int nbVideoFound;
private static long totalInputLength;
private static long totalOutputLength;
private static int totalFileCount;
static void Main(string[] args)
{
ProcessDirectory(new DirectoryInfo(args[0]));
Console.WriteLine("Complete");
if (totalInputLength > 0)
{
Console.WriteLine("In " + totalInputLength.ToString("#,##0"));
Console.WriteLine("Out " + totalOutputLength.ToString("#,##0"));
Console.WriteLine("Compressed size " + 100 * totalOutputLength / totalInputLength + "%");
}
Console.ReadKey();
}
private static void ProcessDirectory(DirectoryInfo parentDirectory)
{
bool firstFile = true;
foreach (var fsi in parentDirectory.GetFileSystemInfos())
{
try
{
var fi = fsi as FileInfo;
if (fi != null && fi.Length>0)
{
if (Path.GetFileNameWithoutExtension(fi.Name).EndsWith(FFMPEG_SUFFIX)) continue;
var ext = fi.Extension.ToLower();
switch (ext)
{
case ".mp4":
// my camera does thumbnails of every video and I don't need or like them
var thumb = new FileInfo(fi.Directory + @"\" + Path.GetFileNameWithoutExtension(fi.Name) + ".jpg");
if (thumb.Exists) thumb.Delete();
break;
case ".mov":
case ".avi":
case ".wmv":
case ".flv":
case ".3gp":
nbVideoFound++;
if (firstFile)
{
firstFile = false;
Console.WriteLine("=== " + parentDirectory.FullName + " ===");
}
FileInfo fo;
if (ProcessFile(fi, out fo))
{
int rate = (int)Math.Round(fo.Length * 100.0 / fi.Length);
if (rate < 3)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("[Too Small] " + fsi.Name + " " + rate + "%");
Console.ForegroundColor = ConsoleColor.Gray;
fo.Delete();
}
else if (rate > 50)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("[Too big] " + fsi.Name + " " + rate + "%");
Console.ForegroundColor = ConsoleColor.Gray;
fo.Delete();
}
else
{
try
{
totalInputLength += fi.Length;
totalOutputLength += fo.Length;
fi.Delete();
var fo2 = new FileInfo(fi.Directory + @"\" + Path.GetFileNameWithoutExtension(fi.Name) + ".mp4");
if (fo2.Exists) fo2.Delete();
fo.MoveTo(fo2.FullName);
totalFileCount++;
if ((totalFileCount % 25) == 0)
{
Console.WriteLine("In " + totalInputLength.ToString("#,##0"));
Console.WriteLine("Out " + totalOutputLength.ToString("#,##0"));
Console.WriteLine("Compressed size " + 100 * totalOutputLength / totalInputLength + "%");
}
Console.WriteLine("[Success] " + fsi.Name + " " + rate + "%");
}
catch (Exception)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("* Failed to copy " + fsi.Name);
Console.ForegroundColor = ConsoleColor.Gray;
}
}
}
else
{
Console.WriteLine("[Failed] " + fsi.Name);
}
break;
}
}
var di = fsi as DirectoryInfo;
if (di != null)
{
ProcessDirectory(di);
}
}
catch (Exception ex)
{
Console.WriteLine("[Failed] " + fsi.Name + " " + ex.Message);
}
}
}
private static bool ProcessFile(FileInfo fi, out FileInfo fo)
{
fo = new FileInfo(fi.Directory + @"\" + Path.GetFileNameWithoutExtension(fi.Name) + " " + FFMPEG_SUFFIX + ".mp4");
if (fo.Exists && fo.Length > (fi.Length / 100))
{
return true;
}
var program = "C:\\Program Files (x86)\\WinFF\\ffmpeg.exe";
var input = "-y -i \"" + fi.FullName + "\"";
var options = " -crf 25.0 -vcodec libx264 -acodec libfaac -ar 48000 -b:a 160k -coder 1 -flags +loop -cmp +chroma -partitions +parti4x4+partp8x8+partb8x8 -me_method hex -subq 6 -me_range 16 -g 250 -keyint_min 25 -sc_threshold 40 -i_qfactor 0.71 -b_strategy 1 -qcomp 0.6 -qmin 0 -qmax 69 -qdiff 4 -bf 3 -refs 8 -direct-pred 3 -trellis 2 -wpredp 2 -rc_lookahead 60 -threads 0";
var output = " \"" + fo.FullName + "\"";
var args = input + options + output;
var psi = new ProcessStartInfo(program, args);
psi.CreateNoWindow = true;
psi.UseShellExecute = false;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
var p = Process.Start(psi);
DisplayOutput(p.StandardError,false);
DisplayOutput(p.StandardOutput,true);
p.WaitForExit();
ClearCurrentConsoleLine();
fo.Refresh();
return (p.ExitCode == 0);
}
private static void DisplayOutput(StreamReader sr, bool error)
{
Task.Run(() =>
{
string line;
while ((line = sr.ReadLine()) != null)
{
if (error)
{
ClearCurrentConsoleLine();
Console.WriteLine(line);
}
else
{
if (line.Length > 78) line = line.Substring(0, 78);
Console.Write(line + "\r");
}
}
});
}
public static void ClearCurrentConsoleLine()
{
int currentLineCursor = Console.CursorTop;
Console.SetCursorPosition(0, Console.CursorTop);
for (int i = 0; i < Console.WindowWidth; i++)
Console.Write(" ");
if (currentLineCursor == Console.CursorTop)
{
//we should not be here, we have scrolled
Console.SetCursorPosition(0, currentLineCursor - 1);
}
else Console.SetCursorPosition(0, currentLineCursor);
}
}
}
它将使用与 'winff' MPEG-4 非常高质量预设相同的参数进行压缩。
输出结果如下:
=== Z:\Users\Public\Pictures\2011\2011-01-23 Galette des rois ===
[Success] Sesame Tree 009.MOV 9%
[Success] Sesame Tree 010.MOV 11%
[Success] Sesame Tree 035.MOV 11%
[Success] Sesame Tree 036.MOV 10%
[Success] Sesame Tree 037.MOV 10%
[Success] Sesame Tree 038.MOV 10%
[Success] Sesame Tree 039.MOV 10%
[Success] Sesame Tree 040.MOV 11%
[Success] Sesame Tree 041.MOV 9%
[Success] Sesame Tree 042.MOV 11%
=== Z:\Users\Public\Pictures\2011\2011-01-24 Sesame Tree ===
[Success] Sesame Tree 009 20020215.MOV 9%
[Success] Sesame Tree 035 59518234.MOV 11%
[Success] Sesame Tree 036 38066230.MOV 10%
[Success] Sesame Tree 037 541614982.MOV 10%
[Success] Sesame Tree 038 65036214.MOV 10%
[Success] Sesame Tree 039 514636214.MOV 10%
[Success] Sesame Tree 040 92674886.MOV 11%
[Success] Sesame Tree 041 22075926.MOV 9%
[Success] Sesame Tree 042 29313510.MOV 11%
[Success] Ballet 041.MOV 8%s\2011\2011-01-30 Celine ===
[Success] Ballet 042.MOV 20%
[Success] Ballet 051.MOV 20%
=== Z:\Users\Public\Pictures\2011\2011-02-05 Pingoins au Zoo ===
[Success] Ballet 010.MOV 12%
[Success] Ballet 020.MOV 11%
[Success] Ballet 021.MOV 9%
[Success] Ballet 022.MOV 9%
[Success] Ballet 023.MOV 7%
=== Z:\Users\Public\Pictures\2011\2011-04-08 Ballet ===
[Success] Ballet 061.MOV 10%
[Success] Ballet 064.MOV 9%
frame= 1133 fps= 42 q=31.0 size= 6037kB time=00:00:36.03 bitrate=1372.6kbit
关注点
该程序在后台使用 FFMPEG 进行压缩。
比特率不是固定的,而是基于质量的。一些缓慢移动的视频比特率可能低至 500kbit/s 或更低,而其他视频可能高达 2000kbit/s 或更高。但质量始终非常好。
历史
这只是我的程序的故事。
它可能对你有所帮助。
如果你对其进行进一步开发,请告诉我。