Streaming ffmpeg.exe stdout - c#

I need to stream the standard output from ffmpeg.exe directly to a web response stream on the fly. I have no problem setting up the command line with Process/RedirectStandardOutput/etc to pipe the output stream.
However, the problem seems to be the output from Process.StandardOutput is not in the correct raw format. Something like this (pseudocode):
var ffpsi = new ProcessStartInfo("ffmpeg.exe", "-i input.mp3 -acodec copy -f mp3 -")
ffpsi.UseShellExecute = false;
ffpsi.RedirectStandardOutput = true;
var ffmpegProcess = new Process();
ffpmpegProcess.StartInfo = ffpsi;
ffmpegProcess.Start();
var outputFile = new FileStream("out.mp3");
ffmpegProcess.StandardOutput.BaseStream.CopyTo(outputFile);
creates a file a little larger than the original and it's clearly not a valid MP3.
I've played with various encodings copying strategies with the base streams and get data from the async callbacks, but nothing seems to work.
Any ideas here? I guess this comes down to how to get the raw binary output from ffmpeg stdout into a .NET stream I can pass to a response stream?

Related

FFMpegCore C# read bytes from file

I am trying to read byte array or stream from mp4/h264 file using "FFMpegCore" library.
I am trying to read file and store it into fileStreamOnlyWithMedia but I have error
Could not write header for output file #0 (incorrect codec parameters ?): Invalid argument"
var fileStreamOnlyWithMedia = new MemoryStream();
FFMpegArguments
.FromFileInput(filePath)
.OutputToPipe(new StreamPipeSink(fileStreamOnlyWithMedia), options => options
.WithVideoCodec(VideoCodec.LibX264).WithoutMetadata().ForceFormat("mp4").WithFastStart()).ProcessSynchronously();
fileBytes = fileStreamOnlyWithMedia.ToArray();
The problem is that the mp4 container requires seeking (because of the required ordering of the content inside the file), which isn't possible when ffmpeg is outputting to a pipe.
You could try with vp9 and mkv instead
For more information, see this answer

Access to StandardInput from NRECO.VideoConverter?

I'm currently using the answer to this question to pipe a string of bitmaps into ffmpeg. It requires redirecting StandardInput stream and writing to it.
Is something similar available with NRECO.VideoConverter? Is there a way to get either access to the running process, or access to just the StandardInput base stream?
If you want to provide input data to stdin or read output data from stdout (or both) you may use ConvertLiveMedia method; it has overloads for different usage scenarios:
var videoConv = new FFMpegConverter();
var ffMpegTask = videoConv.ConvertLiveMedia(
"rawvideo",
h264stream,
"h264",
new ConvertSettings() {
CustomInputArgs = String.Format(" -pix_fmt bgr24 -video_size 640x480 -framerate 5 ",
frameBmp.Width, frameBmp.Height)
});
ffMpegTask.Start();
ffMpegTask.Write( bmpBytes ); // call N times for each input frame. Image size should be exactly 640x480
ffMpegTask.Stop();
You can adopt this code snippet for "image2pipe" if needed.

Decode Stream to CSV in Python by Byte (Translate from C# code)

I am trying to consume a streamed response in Python from a soap API, and output a CSV file. The response outputs a string coded in base 64, which I do not know what to do with. Also the api documentation says that the response must be read to a destination buffer-by-buffer.
Here is the C# code was provided by the api's documentation:
byte[] buffer = new byte[4000];
bool endOfStream = false;
int bytesRead = 0;
using (FileStream localFileStream = new FileStream(destinationPath, FileMode.Create, FileAccess.Write))
{
using (Stream remoteStream = client.DownloadFile(jobId))
{
while (!endOfStream)
{
bytesRead = remoteStream.Read(buffer, 0, buffer.Length);
if (bytesRead > 0)
{
localFileStream.Write(buffer, 0, bytesRead);
totalBytes += bytesRead;
}
else
{
endOfStream = true;
}
}
}
}
I have tried many different things to get this stream to a readable csv file, but non have worked.
with open('test.csv', 'w') as f: f.write(FileString)
Returns a csv with the base64 string spread over multiple lines
Here is my latest attempt:
with open('csvfile13.csv', 'wb') as csvfile:
FileString = client.service.DownloadFile(yyy.JobId, False)
stream = io.BytesIO(str(FileString))
with open(stream,"rt",4000) as readstream:
csvfile.write(readstream)
This produces the error:
TypeError: coercing to Unicode: need string or buffer, _io.BytesIO
Any help would be greatly appreciated, even if it is just to point me in the right direction. I will be ensure to award the points to whoever is the most helpful, even if I do not completely solve the issue!
I have asked several questions similar to this one, but I have yet to find an answer that works completely:
What is the Python equivalent to FileStream in C#?
Write Streamed Response(file-like object) to CSV file Byte by Byte in Python
How to replicate C# 'byte' and 'Write' in Python
Let me know if you need further clarification!
Update:
I have tried print(base64.b64decode(str(FileString)))
This gives me a page full of webdings like
]�P�O�J��Y��KW �
I have also tried
for data in client.service.DownloadFile(yyy.JobId, False):
print data
But this just loops through the output character by characater like any other string.
I have also managed to get a long string of bytes like \xbc\x97_D\xfb(not actual bytes, just similar format) by decoding the entire string, but I do not know how to make this readable.
Edit: Corrected the output of the sample python, added more example code, formatting
It sounds like you need to use the base64 module to decode the downloaded data.
It might be as simple as:
with open(destinationPath, 'w') as localFile:
remoteFile = client.service.DownloadFile(yyy.JobId, False)
remoteData = str(remoteFile).decode('base64')
localFile.write(remoteData)
I suggest you break the problem down and determine what data you have at each stage. For example what exactly are you getting back from client.service.DownloadFile?
Decoding your sample downloaded data (given in the comments):
'UEsYAItH7brgsgPutAG\AoAYYAYa='.decode('base64')
gives
'PK\x18\x00\x8bG\xed\xba\xe0\xb2\x03\xee\xb4\x01\x80\xa0\x06\x18\x01\x86'
This looks suspiciously like a ZIP file header. I suggest you rename the file .zip and open it as such to investigate.
If remoteData is a ZIP something like the following should extract and write your CSV.
import io
import zipfile
remoteFile = client.service.DownloadFile(yyy.JobId, False)
remoteData = str(remoteFile).decode('base64')
zipStream = io.BytesIO(remoteData)
z = zipfile.ZipFile(zipStream, 'r')
csvData = z.read(z.infolist()[0])
with open(destinationPath, 'w') as localFile:
localFile.write(csvData)
Note: BASE64 can have some variations regarding padding and alternate character mapping but once you can see the data it should be reasonably clear what you need. Of course carefully read the documentation on your SOAP interface.
Are you sure FileString is a Base64 string? Based on the source code here, suds.sax.text.Text is a subclass of Unicode. You can write this to a file as you would a normal string but whatever you use to read the data from the file may corrupt it unless it's UTF-8-encoded.
You can try writing your Text object to a UTF-8-encoded file using io.open:
import io
with io.open('/path/to/my/file.txt', 'w', encoding='utf_8') as f:
f.write(FileString)
Bear in mind, your console or text editor may have trouble displaying non-ASCII characters but that doesn't mean they're not encoded properly. Another way to inspect them is to open the file back up in the Python interactive shell:
import io
with io.open('/path/to/my/file.txt', 'r', encoding='utf_8') as f:
next(f) # displays the representation of the first line of the file as a Unicode object
In Python 3, you can even use the built-in csv to parse the file, however in Python 2, you'll need to pip install backports.csv because the built-in module doesn't work with Unicode objects:
from backports import csv
import io
with io.open('/path/to/my/file.txt', 'r', encoding='utf_8') as f:
r = csv.reader(f)
next(r) # displays the representation of the first line of the file as a list of Unicode objects (each value separated)

Magick.NET convert raw images

I use Magick.NET for processing files. And now I need convert raw image format (such as .dng, .3fr, .cr2, .raw, .ptx, etc.) to simple jpg for generating preview on the site. I found example in documentation here
but it's not working. I put dcraw.exe to Magick.NET dll's but always got error in this moment:
//code
using (var originalImg = new MagickImage(abspath))...
//text of error
InnerException = {"iisexpress.exe: FailedToExecuteCommand `dcraw.exe -6 -w -O \"C:/Users/A8F50~1.CHE/AppData/Local/Temp/magick-29445L9OLy_DVIQq.ppm\" \"C:/Users/A8F50~1.CHE/AppData/Local/Temp/magick-294458yvxz2HRaYX\"' (-1) # error/delegate.c/ExternalDelegateCommand/484"}
Message = "iisexpress.exe: UnableToOpenBlob 'C:/Users/A8F50~1.CHE/AppData/Local/Temp/magick-29445L9OLy_DVIQq.ppm': No such file or directory # error/blob.c/OpenBlob/2684"
Is anyone faced with such problem? I have no idea why this shit happens. I wasted a lot of time for this and I'll be glad if you'll help me with this problem
you have to use a FileStream object instead the file path... That will work for me.
Try this:
FileStream fileStream = new FileStream(#"C:\QRcodes\IMG_9540.CR2", FileMode.Open);
using (MagickImage magickImage = new MagickImage(fileStream))
{
byte[] imageBytes = magickImage.ToByteArray();
Console.WriteLine("bytes in image: " + imageBytes.Length);
Console.ReadKey();
}
greetings
Markus
This is not related to the file stream or actual physical path. you can call the MagickImage constructor with a physical path. The problem and the error message you received is that your code cannot find the file. It may be because of the permission or the way you pass the address of the file or any thing that prevent your code to reach the file.
One another things: Converting the MagickImage to ByteArray is highly time consuming and is heavy process in the system. If you try an image with 20000 pixels you will see the result.

C# WCF Video Streaming from growing file?

Been pulling my hair out over what should have been a quick and easy task.
I have a self-hosted WCF service in which I need to implement real-time video transcoding, the transcoding isn't a problem as such, using FFMpeg to a local temp file.
Quick sample of what my code looks like;
public Stream StreamMedia(int a)
{
String input = #"\media\" + a + ".mkv";
String output = #"\temp\transcoded\" + a + DateTime.Now.Ticks.ToString() + ".wmv";
ProcessStartInfo pi = new ProcessStartInfo("ffmpeg.exe");
pi.Arguments = "-i " + input + " -y -ab 64k -vcodec wmv2 -b 800k -mbd 2 -cmp 2 -subcmp 2 -s 320x180 -f asf " + output;
Process p = new Process;
p.StartInfo = pi;
p.Start();
Thread.Sleep(2500);
return new FileStream(output, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
}
The problem I am facing is that the returned Stream only gives me what was written to the file when it is returned - resulting in a rather short video file :)
I've played around with the obvious here, but no matter what I do it will only return what's available there and then.
What I need to happen is for the Stream to be returned with no respect to the actual current lenght of the output file - there is other code involved which makes sure the data is never sent to the client faster than what FFMpeg manages to encode, so basically I just need an open-ended stream.
Any takers?
One solution would be to create your custom Stream class which would wrap around the file from disk; BUT, there's also the concurrency issue, meaning that you need some locking mechanism as for the writing process (video transcoder) to properly share the file with your FileStream.
Is it possible for your transcoder to create multi-volume output? If so, then your lucky and this would work with (almost) no pain at all, just do the streaming of the volume N, then the transcoder writes the volume N + 1, and you'll not have any file access concurrency issues.
happy coding!
- Adrian
The simplest may be to use the Streaming Media service that is built into the operating system. See: http://technet.microsoft.com/en-us/windowsserver/dd448620
The other way to do it would be not to read from the file, but send the stream that is writing to the file, straight out to the client.
What is obvious is, this cannot be done via file system. You need a dynamic solution.
You can do it via your own made media service. In your case it could be a WCF or windows service.
This service should be responsible for both writing to the file (as data receives) and streaming.

Categories

Resources