c# - 为什么我在使用 ffmpeg 和管道实时创建视频文件时得到奇怪的视频文件?

标签 c# .net winforms video ffmpeg

这里的目标是实时创建压缩的 mp4 视频文件。
我将屏幕截图作为位图类型保存在我的硬盘上。
我想创建 mp4 文件并实时压缩 mp4 视频文件。

问题是我得到的视频文件看起来很奇怪。
结果如下:Strange Video File

我正在使用带有参数的 ffmpeg 的类。

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 -pix_fmt yuv420p -video_size 1920x1080 -i \\.\pipe\mytestpipe -map 0 -c:v mpeg4 -r " + BitmapRate + " " + outPath;
                //psi.Arguments = @"-framerate 1/5 -i -c:v libx264 -r 30 -pix_fmt yuv420p \\.\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();
        }
    }
}

然后我在这个类中使用 PushFrame 方法:
public Bitmap GetScreenShot(string folder, string name)
    {
        _screenShot = new Bitmap(GetScreen());
        System.GC.Collect();
        System.GC.WaitForPendingFinalizers();
        string ingName = folder + name +  images.counter.ToString("D6") + ".bmp";
        _screenShot.Save(ingName,System.Drawing.Imaging.ImageFormat.Bmp);
        fmpeg.PushFrame(_screenShot);
        _screenShot.Dispose();

        return _screenShot;
    }

硬盘上的位图很好,我可以编辑/打开看到它们。
当使用命令提示符并手动键入 ffmpeg 命令时,它会压缩并创建一个 mp4 视频文件。

但是当使用 Ffmpeg 类时,我使用 PushFrame 方法创建了这个奇怪的视频文件。

这是我的 OneDrive 的链接,其中包含 10 个用于测试的屏幕截图图像文件:

screenshots rar

播放视频文件时的视频文件截图示例:
看起来很波涛汹涌。硬盘上的 Bitmaps 每一张都是 1920x1080 和 Bit depth 32

但它在视频文件中看起来不像:

choppy image

这是我正在使用的论点:
psi.Arguments = @"-f rawvideo -vcodec rawvideo -pix_fmt rgb24 -video_size 1920x1080 -i \\.\pipe\mytestpipe -map 0 -c:v mpeg4 -r " + BitmapRate + " " + outPath;

视频大小非常小 1.24 MB

最佳答案

您需要同时设置 -f rawvideo表示您用于输入的容器类型,以及 -vcodec rawvideo这对您推送到 ffmpeg 的视频数据也是如此.否则,ffmpeg 将尝试检测您正在使用的容器类型,这可能无法按预期工作。

此外,正如@Ely 评论的那样,您需要设置 -pix_fmt rgb24 ,因为这是您发送的图像的格式。

另请注意,您可以通过使用 -v debug 获得有关 ffmpeg 正在做什么的更好信息。范围。

关于c# - 为什么我在使用 ffmpeg 和管道实时创建视频文件时得到奇怪的视频文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31127286/

相关文章:

c# - "Possible compare of value type with ' null'”怎么办?

.net - F# 中的 OrderBy ThenBy

.net - Azure AD MSAL 中的范围、角色和组之间的区别

c# - 从线程更新表单时,表单中的空白组件

C# dt.Compute() 在某些乘法上不能正常工作

c# - Windows 8 应用程序 C# 'string' 不包含 'Copy' 的定义

c# - 如何在我的 DataGridViewImageColumn 中添加图像?

c# - 一致取消 Async CancellationTokenSource 的最佳实践

c# - 当垃圾收集器在堆中移动数据时,引用是否会更新?

c# - 根据绑定(bind)源中的外键显示查找值