C# FFMPEG - How to get extracted frames without save in file system - c#

I need to process frames from video and live stream without saving into file system.
C# I am trying using below code, but not getting frames
Process proc = new Process();
proc.StartInfo.FileName = #"E:\ffmpeg\bin\ffmpeg.exe";
proc.StartInfo.Arguments = String.Format(#"-i E:\ffmpeg\bin\video.mp4 -f rawvideo pipe:1");
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardOutput = true;
proc.Start();
proc.OutputDataReceived += (sender, args) => DataReceived(args);
proc.ErrorDataReceived += (sender, args) => DataReceived(args);
I can get frames in nodejs successfully using below code
const spawnProcess = require('child_process').spawn
ffmpeg = spawnProcess('E:\\ffmpeg\\bin\\ffmpeg.exe', [
'-i', 'rtsp://username:password#192.168.6.37/ch1/main/sub-stream',
'-vcodec', 'mjpeg','-vf','fps=2',
'-f', 'rawvideo',
//'-s', HW, // size of one frame
'pipe:1'
]);
ffmpeg.stderr.pipe(logStream);
let frames = [];
ffmpeg.stdout.pipe(new ExtractFrames("FFD8FF")).on('data', (data) => {
var fName=new Date().getTime()+".png";
(
async () => await ProcessFrame(Buffer.from(data).toString('base64'))
)();
})
Same thing await ProcessFrame(Buffer.from(data).toString('base64')) I want in C#

Related

How to redirect input and output of existing process c#

There are two endpoints, I am thinking to add one endpoint to start the process and another is to do process communication(stdin/stdin). Is it possible? Or should I use some other ways to do this like websocket?
I am trying to start a process as below.
Process process = new Process();
ProcessStartInfo procStartInfo = new ProcessStartInfo("/bin/sh");
procStartInfo.RedirectStandardError = true;
procStartInfo.RedirectStandardOutput = true;
procStartInfo.RedirectStandardInput = true;
procStartInfo.UseShellExecute = false;
procStartInfo.Arguments = "-c " + Constants.CMDName + args;
process.StartInfo = procStartInfo;
Console.WriteLine("Start res: " + process.Start());
Process is getting started but when I am trying to do stdin/out like below I am getting an error saying StandardIn not redirected.
Process[] processes = Process.GetProcessesByName(Constants.VSDebugProcessName);
if (processes.Length == 0)
{
throw new Exception("Process is not running");
}
Console.WriteLine(JsonSerializer.Serialize(processes[0].StartInfo));
var process = processes[0];
StreamWriter sw = process.StandardInput;
await sw.WriteLineAsync(JsonSerializer.Serialize(payload));
Should I combine these two endpoints or is there any other workaround for this issue?
You can set EnableRaisingEvents = true in the ProcessStartInfo, and add a handler on the process’s OutputDataReceived message to collect the output. The following snippet illustrates the procedure. It also handles error output (stderr).
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = fileName,
Arguments = arguments,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
},
EnableRaisingEvents = true,
};
var output = new StringBuilder();
var error = new StringBuilder();
process.OutputDataReceived += (_, args) =>
{
output.AppendLine(args.Data);
};
process.ErrorDataReceived += (_, args) =>
{
error.AppendLine(args.Data);
};
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
ResultsText.Value = output.ToString();

How to execute a terminal command in Xamarin.Mac and read-in its output

We are writing a Xamarin.Mac application. We need to execute a command like "uptime" and read it's output into an application to parse.
Could this be done? In Swift and Objective-C there is NTask, but I don't seem to be able to find any examples in C#.
Under Mono/Xamarin.Mac, you can the "standard" .Net/C# Process Class as the Process gets mapped to the underlaying OS (OS-X For Mono, MonoMac and Xamarin.Mac, and Mono for *nix).
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "Write500Lines.exe";
p.Start();
// To avoid deadlocks, always read the output stream first and then wait.
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
Xamarin: https://developer.xamarin.com/api/type/System.Diagnostics.Process/
MSDN: https://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.redirectstandardoutput%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396
Example from my OS-X C# code, but it is cross-platform as it works as is under Windows/OS-X/Linux, just the executable that you are running changes across the platforms.
var startInfo = new ProcessStartInfo () {
FileName = Path.Combine (commandPath, command),
Arguments = arguments,
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
RedirectStandardInput = true,
UserName = System.Environment.UserName
};
using (Process process = Process.Start (startInfo)) { // Monitor for exit}
process.WaitForExit ();
using (var output = process.StandardOutput) {
Console.Write ("Results: {0}", output.ReadLine ());
}
}
Here is an example taken from Xamarin forum:
var pipeOut = new NSPipe ();
var t = new NSTask();
t.LaunchPath = launchPath;
t.Arguments = launchArgs;
t.StandardOutput = pipeOut;
t.Launch ();
t.WaitUntilExit ();
t.Release ();
var result = pipeOut.ReadHandle.ReadDataToEndOfFile ().ToString ();

c# generate thumbnails from raw images

I have an Asp.net Web forms application,when upload raw image file with format
{ "cr2", "raw", "dng", "nef", "raf", "orf", "srf", "sr2", "arw", "k25", "kdc", "dcr","mos",
"pnx", "crw", "mrw", "pef" , "mef" , "rw2","a7","a7r"}
How can i generate thumbnails from raw image?
You can use dcraw.exe application run on your .net application.you can download it in the link.
First save raw image in local disk and use the code:
string dcrawPath = "dcraw.exe";
ProcessStartInfo startInfo = new ProcessStartInfo();
string inputImagePath= "input Raw Image Path/";
string outputImagePath = "output Raw Image Path/";
startInfo.RedirectStandardError = true;
startInfo.RedirectStandardOutput = true;
startInfo.CreateNoWindow = true;
startInfo.UseShellExecute = false;
startInfo.FileName = dcrawPath;
string commandArg1 = string.Format("\"{0}\"", outputImagePath);
string commandArg2 = string.Format("\"{0}\"", inputImagePath);
startInfo.Arguments = "-u ";
startInfo.Arguments += commandArg1;
startInfo.Arguments += " -e ";
startInfo.Arguments += commandArg2;
startInfo.Arguments += " -T";
using (Process exeProcess = Process.Start(startInfo))
{
exeProcess.WaitForExit();
string stdout = exeProcess.StandardOutput.ReadToEnd();
string stderr = exeProcess.StandardError.ReadToEnd();
Console.WriteLine("Exit code : {0}", exeProcess.ExitCode);
}
Put raw image in inputImagePath variable
You can find image in outputImagePath variable
Try GDPicture.NET component. It supports different RAW formats and easy for use, but is not free. To generate thumbnail use CreateThumbnail or CreateThumbnailHQ method of GdPictureImaging class:
using (var imaging = new GdPictureImaging())
{
int pictureId = imaging.CreateGdPictureImageFromFile(filepath);
if (pictureId == 0)
{
MessageBox.Show("Error: " + imaging.GetStat().ToString());
return;
}
int thumbnailImgId = imaging.CreateThumbnail(pictureId, 20, 20);
imaging.SaveAsPNG(thumbnailImgId, "thumbnail.png");
imaging.ReleaseGdPictureImage(thumbnailImgId);
imaging.ReleaseGdPictureImage(pictureId);
}

Cannot access the file because it is being used by another process using ffmpeg

I am getting the error:
Cannot access the file because it is being used by another process
I have a C# desktop app.
I am using the Process class to convert images to a video file by using FFMPEG.
This is my code:
using (Process serverBuild = new Process())
{
serverBuild.StartInfo.WorkingDirectory = Environment.CurrentDirectory;
string args = " -f image2 -i " + {path} + "\\img%05d.jpg -s 352x288 -filter:v \"setpts=5.0*PTS\" -y " + {path}\\File.mp4;
serverBuild.StartInfo.Arguments = args;
serverBuild.StartInfo.FileName = "ffmpeg.exe";
serverBuild.StartInfo.UseShellExecute = false;
serverBuild.StartInfo.RedirectStandardOutput = true;
serverBuild.StartInfo.RedirectStandardError = true;
serverBuild.StartInfo.CreateNoWindow = true;
serverBuild.Start();
// string output = serverBuild.StandardOutput.ReadToEnd();
//Log.Instance.Debug(serverBuild.StandardError.ReadToEnd());
serverBuild.WaitForExit();
serverBuild.Close();
}
Directory.Delete(ExportRoute + FFMPEGPacket.LicenseKey + "\\" + FFMPEGPacket.Guid, true);
//which raise the error..
The images are all deleted but the File.Mp4 is not and that is the error. The error says that the newly created MP4 file cannot be deleted.
NB
This is partial code to illustrate the error
You may try the following code to create the file (it worked for me):
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = exe_path;
// replace your arguments here
psi.Arguments = string.Format(#" arguments ")
psi.CreateNoWindow = true;
psi.ErrorDialog = true;
psi.UseShellExecute = false;
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.RedirectStandardOutput = true;
psi.RedirectStandardInput = false;
psi.RedirectStandardError = true;
Process exeProcess = Process.Start(psi);
exeProcess.PriorityClass = ProcessPriorityClass.High;
string outString = string.Empty;
exeProcess.OutputDataReceived += (s, e) =>
{
outString += e.Data;
};
exeProcess.BeginOutputReadLine();
string errString = exeProcess.StandardError.ReadToEnd();
Trace.WriteLine(outString);
Trace.TraceError(errString);
exeProcess.WaitForExit();
exeProcess.Close();
exeProcess.Dispose();
FFMPEG might still be rendering the creation of video from images after it closes, so it might be worth if you place a Threading.Thead.Sleep(5000) 5 secs; before delete.
Try that:
File.WriteAllBytes(path, new byte[0]);
File.Delete(path);

Partially read standard output of another process created from c# application

I have a GUI application within which i'm spawning a console application using Process class.
Process p1 = new Process();
p1.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p1.StartInfo.CreateNoWindow = true;
p1.StartInfo.UseShellExecute = false;
p1.StartInfo.FileName = Path.Combine(basepath, "abc.exe");
p1.StartInfo.Arguments = "/pn abc.exe /f \"temp1.txt\"";
p1.StartInfo.RedirectStandardError = true;
p1.StartInfo.RedirectStandardInput = true;
p1.StartInfo.RedirectStandardOutput = true;
p1.OutputDataReceived += new DataReceivedEventHandler(outputreceived);
p1.ErrorDataReceived += new DataReceivedEventHandler(errorreceived);
p1.Start();
tocmd = p1.StandardInput;
p1.BeginOutputReadLine();
p1.BeginErrorReadLine();
Now i have a problem that, though it reads the console output asynchronously but it seems to fire the event only when the internal buffer is filled with some amount. I want it to display data as it comes. If there's 10 bytes in buffer, let it display the 10 bytes. My program implements sleep() call internally, so i need to print the data till it goes to sleep.
How can i do it?
=============
As it was mentioned the output is line buffered, i tried the following change in the code
p1.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p1.StartInfo.CreateNoWindow = true;
p1.StartInfo.UseShellExecute = false;
p1.StartInfo.FileName = Path.Combine(basepath, "abc.exe");
p1.StartInfo.Arguments = pnswitch + " /f \"temp1.txt\"";
p1.StartInfo.RedirectStandardError = false;
p1.StartInfo.RedirectStandardInput = true;
p1.StartInfo.RedirectStandardOutput = true;
p1.Start();
tocmd = p1.StandardInput;
MethodInvoker mi = new MethodInvoker(readout);
mi.BeginInvoke(null, p1);
and inside readout i wrote
void readout()
{
string str;
while ((str = p1.StandardOutput.ReadLine()) != null)
{
richTextBox1.Invoke(new UpdateOutputCallback(this.updateoutput), new object[] { str });
p1.StandardOutput.BaseStream.Flush();
}
}
So i think it now monitors when each line is written and it prints it right? this too didn't work. Any thing wrong there?
The Output and Error Data received is line buffered, and will only fire when a newline is added.
Your best bet is to use you own reader that can read the input, byte by byte. Obvioulsly, this would have to be non-blocking :)
In order to achieve this, you must use synchronous read operations on a redirected stream.
Your code would look like this (MSDN Sample):
// Start the child process.
Process p = new Process();
// Redirect the output stream of the child process.
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "Write500Lines.exe";
p.Start();
// Do not wait for the child process to exit before
// reading to the end of its redirected stream.
// p.WaitForExit();
// Read the output stream first and then wait.
**string output = p.StandardOutput.ReadToEnd();**
p.WaitForExit();
In order to achieve async behavior you would have to use some threads.
MSDN Article here

Categories

Resources