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

时间:2015-06-29 23:37:52

标签: 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

播放视频文件时,视频文件中的示例截图: 看起来很不稳定。硬盘上的位图每个都是1920x1080,位深度为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

1 个答案:

答案 0 :(得分:0)

You need to set both, -f rawvideo which indicates the kind of container you are using for your input, and -vcodec rawvideo which does the same for the video data you are pushing to ffmpeg. Otherwise, ffmpeg will try to detect the type of container you are using, and that probably won't work as expected.

Also, as @Ely commented, you need to set the -pix_fmt rgb24, as that is the format of the images you are sending.

Also note that you can get better information about what ffmpeg is doing by using the -v debug parameter.