当使用 ffmpeg 从批量图像中实时压缩和创建 mpeg4 视频文件时,获得低质量视频如何提高质量?
When using ffmpeg to compress and create in real time mpeg4 video file from bathc of images getting low quality video how can i improve quality?
这里的目标是实时创建压缩的 mp4 视频文件。我将屏幕截图保存为硬盘上的位图类型。我想创建mp4文件并实时压缩mp4视频文件。
using System;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.IO.Pipes;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.IO;
using DannyGeneral;
namespace Youtube_Manager
{
class Ffmpeg
{
NamedPipeServerStream p;
String pipename = "mytestpipe";
System.Diagnostics.Process process;
string ffmpegFileName = "ffmpeg.exe";
string workingDirectory;
public Ffmpeg()
{
workingDirectory = Path.GetDirectoryName(Application.ExecutablePath);
Logger.Write("workingDirectory: " + workingDirectory);
if (!Directory.Exists(workingDirectory))
{
Directory.CreateDirectory(workingDirectory);
}
ffmpegFileName = Path.Combine(workingDirectory, ffmpegFileName);
Logger.Write("FfmpegFilename: " + ffmpegFileName);
}
public void Start(string pathFileName, int BitmapRate)
{
try
{
string outPath = pathFileName;
p = new NamedPipeServerStream(pipename, PipeDirection.Out, 1, PipeTransmissionMode.Byte);
ProcessStartInfo psi = new ProcessStartInfo();
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.UseShellExecute = false;
psi.CreateNoWindow = false;
psi.FileName = ffmpegFileName;
psi.WorkingDirectory = workingDirectory;
psi.Arguments = @"-f rawvideo -vcodec rawvideo -pix_fmt rgb24 -video_size 1920x1080 -i \.\pipe\mytestpipe -map 0 -c:v mpeg4 -r " + BitmapRate + " " + outPath;
process = Process.Start(psi);
process.EnableRaisingEvents = false;
psi.RedirectStandardError = true;
p.WaitForConnection();
}
catch (Exception err)
{
Logger.Write("Exception Error: " + err.ToString());
}
}
public void PushFrame(Bitmap bmp)
{
try
{
int length;
// Lock the bitmap's bits.
//bmp = new Bitmap(1920, 1080);
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
//Rectangle rect = new Rectangle(0, 0, 1280, 720);
System.Drawing.Imaging.BitmapData bmpData =
bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly,
bmp.PixelFormat);
int absStride = Math.Abs(bmpData.Stride);
// Get the address of the first line.
IntPtr ptr = bmpData.Scan0;
// Declare an array to hold the bytes of the bitmap.
//length = 3 * bmp.Width * bmp.Height;
length = absStride * bmpData.Height;
byte[] rgbValues = new byte[length];
//Marshal.Copy(ptr, rgbValues, 0, length);
int j = bmp.Height - 1;
for (int i = 0; i < bmp.Height; i++)
{
IntPtr pointer = new IntPtr(bmpData.Scan0.ToInt32() + (bmpData.Stride * j));
System.Runtime.InteropServices.Marshal.Copy(pointer, rgbValues, absStride * (bmp.Height - i - 1), absStride);
j--;
}
p.Write(rgbValues, 0, length);
bmp.UnlockBits(bmpData);
}
catch(Exception err)
{
Logger.Write("Error: " + err.ToString());
}
}
public void Close()
{
p.Close();
}
}
}
我硬盘上的Bitmaps图像文件每一个都是1920x1080和位深度32。
视频文件在硬盘上,大小为1.24MB
这是我在播放视频文件时截取的截图。
可见质量有多差
这是一个 link 的 10 张屏幕截图图像,我正在使用从视频文件创建的屏幕截图。它们是位图。
它与参数有关:
当我 运行 命令提示符 window 立即关闭程序时,此行不起作用。我什至看不到是否有任何 erorr/s 命令提示 window 关闭太快。
psi.Arguments = @"-f libx264 -vcodec libx264 -pix_fmt bgra -video_size 1920x1080 -i \.\pipe\mytestpipe -map 0 -c:v mpeg4 -r " + BitmapRate + " " + outPath;
当我使用这个参数时,它可以工作,但制作的视频质量很差:
psi.Arguments = @"-f rawvideo -pix_fmt bgra -video_size 1920x1080 -i \.\pipe\mytestpipe -map 0 -c:v mpeg4 -r " + BitmapRate + " " + outPath;
您弄错了输入参数和输出参数。
命令的第一部分应该是:
@"-f rawvideo -pix_fmt bgra -video_size 1920x1080 -i \.\pipe\mytestpipe
这告诉 ffmpeg 期待一个管道,其中包含使用 bgra 像素格式和 1080p 大小的原始图像。
然后是第二部分——输出参数——以获得更好的质量:
-c:v libx264 -crf 20 -r " + BitmapRate + " " + outPath;
确保 outPath 具有 .mp4 或 .mkv 扩展名,因为 H.264 无法混合到 .avi 中。
您可以根据需要调整crf的值。较低的值将具有更好的质量和更大的文件大小,较高的值则相反。我建议 crf 值在 17-24 范围内。
这里的目标是实时创建压缩的 mp4 视频文件。我将屏幕截图保存为硬盘上的位图类型。我想创建mp4文件并实时压缩mp4视频文件。
using System;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.IO.Pipes;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.IO;
using DannyGeneral;
namespace Youtube_Manager
{
class Ffmpeg
{
NamedPipeServerStream p;
String pipename = "mytestpipe";
System.Diagnostics.Process process;
string ffmpegFileName = "ffmpeg.exe";
string workingDirectory;
public Ffmpeg()
{
workingDirectory = Path.GetDirectoryName(Application.ExecutablePath);
Logger.Write("workingDirectory: " + workingDirectory);
if (!Directory.Exists(workingDirectory))
{
Directory.CreateDirectory(workingDirectory);
}
ffmpegFileName = Path.Combine(workingDirectory, ffmpegFileName);
Logger.Write("FfmpegFilename: " + ffmpegFileName);
}
public void Start(string pathFileName, int BitmapRate)
{
try
{
string outPath = pathFileName;
p = new NamedPipeServerStream(pipename, PipeDirection.Out, 1, PipeTransmissionMode.Byte);
ProcessStartInfo psi = new ProcessStartInfo();
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.UseShellExecute = false;
psi.CreateNoWindow = false;
psi.FileName = ffmpegFileName;
psi.WorkingDirectory = workingDirectory;
psi.Arguments = @"-f rawvideo -vcodec rawvideo -pix_fmt rgb24 -video_size 1920x1080 -i \.\pipe\mytestpipe -map 0 -c:v mpeg4 -r " + BitmapRate + " " + outPath;
process = Process.Start(psi);
process.EnableRaisingEvents = false;
psi.RedirectStandardError = true;
p.WaitForConnection();
}
catch (Exception err)
{
Logger.Write("Exception Error: " + err.ToString());
}
}
public void PushFrame(Bitmap bmp)
{
try
{
int length;
// Lock the bitmap's bits.
//bmp = new Bitmap(1920, 1080);
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
//Rectangle rect = new Rectangle(0, 0, 1280, 720);
System.Drawing.Imaging.BitmapData bmpData =
bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly,
bmp.PixelFormat);
int absStride = Math.Abs(bmpData.Stride);
// Get the address of the first line.
IntPtr ptr = bmpData.Scan0;
// Declare an array to hold the bytes of the bitmap.
//length = 3 * bmp.Width * bmp.Height;
length = absStride * bmpData.Height;
byte[] rgbValues = new byte[length];
//Marshal.Copy(ptr, rgbValues, 0, length);
int j = bmp.Height - 1;
for (int i = 0; i < bmp.Height; i++)
{
IntPtr pointer = new IntPtr(bmpData.Scan0.ToInt32() + (bmpData.Stride * j));
System.Runtime.InteropServices.Marshal.Copy(pointer, rgbValues, absStride * (bmp.Height - i - 1), absStride);
j--;
}
p.Write(rgbValues, 0, length);
bmp.UnlockBits(bmpData);
}
catch(Exception err)
{
Logger.Write("Error: " + err.ToString());
}
}
public void Close()
{
p.Close();
}
}
}
我硬盘上的Bitmaps图像文件每一个都是1920x1080和位深度32。
视频文件在硬盘上,大小为1.24MB
这是我在播放视频文件时截取的截图。 可见质量有多差
这是一个 link 的 10 张屏幕截图图像,我正在使用从视频文件创建的屏幕截图。它们是位图。
它与参数有关: 当我 运行 命令提示符 window 立即关闭程序时,此行不起作用。我什至看不到是否有任何 erorr/s 命令提示 window 关闭太快。
psi.Arguments = @"-f libx264 -vcodec libx264 -pix_fmt bgra -video_size 1920x1080 -i \.\pipe\mytestpipe -map 0 -c:v mpeg4 -r " + BitmapRate + " " + outPath;
当我使用这个参数时,它可以工作,但制作的视频质量很差:
psi.Arguments = @"-f rawvideo -pix_fmt bgra -video_size 1920x1080 -i \.\pipe\mytestpipe -map 0 -c:v mpeg4 -r " + BitmapRate + " " + outPath;
您弄错了输入参数和输出参数。
命令的第一部分应该是:
@"-f rawvideo -pix_fmt bgra -video_size 1920x1080 -i \.\pipe\mytestpipe
这告诉 ffmpeg 期待一个管道,其中包含使用 bgra 像素格式和 1080p 大小的原始图像。
然后是第二部分——输出参数——以获得更好的质量:
-c:v libx264 -crf 20 -r " + BitmapRate + " " + outPath;
确保 outPath 具有 .mp4 或 .mkv 扩展名,因为 H.264 无法混合到 .avi 中。
您可以根据需要调整crf的值。较低的值将具有更好的质量和更大的文件大小,较高的值则相反。我建议 crf 值在 17-24 范围内。