Repeat Audio Backgorund In Video file Using ffmpeg - c#

My program allow user to insert bunch of images and one audio file, then can generate them into a video file. My program also allow user to provide duration for each images.
I am able to adding audio background into video output, but when video length is more longer than audio length, audio is not looping.
Also when audio length is more longer than video length, the video output will show blank till the end of audio.
Create Video
public bool CreateVideo(string name, List<string> imgs)
{
Bitmap bitmap = (Bitmap)null;
try
{
if (!Directory.Exists(this.outputFolder + "\\temp"))
Directory.CreateDirectory(this.outputFolder + "\\temp");
int num = this.rand.Next(this.delayMin, this.delayMax + 1);
List<string> stringList = new List<string>((IEnumerable<string>)imgs);
if (this.randomizeImages)
this.Shuffle((IList)stringList);
if (!string.IsNullOrEmpty(this.waterImage) && File.Exists(this.waterImage))
bitmap = (Bitmap)Image.FromFile(this.waterImage, true);
if (!string.IsNullOrEmpty(this.introImage))
{
int index = stringList.IndexOf(this.introImage);
if (index > 0)
{
string str = stringList[index];
stringList[index] = stringList[0];
stringList[0] = str;
}
}
for (int position = 0; position < stringList.Count; ++position)
this.ApplyWatermarkImage(stringList[position], position, (Image)bitmap);
if (bitmap != null)
bitmap.Dispose();
string str1 = "";
if (!string.IsNullOrEmpty(this.audioFile))
{
str1 = " -i \"" + this.audioFile + "\" -ar 22050 -ab 64k ";
if (this.GetAudioLength(this.audioFile) > num * stringList.Count)
str1 += "-shortest ";
}
string str2 = this.outputFolder + "\\" + name + ".avi";
ProcessStartInfo processStartInfo = new ProcessStartInfo(Environment.CurrentDirectory + "\\sm\\ffmpeg.exe", str1 + "-fflags +genpts -r 1/" + (object)num + " -b 32K -f image2 -i \"" + this.outputFolder + "\\temp\\%3d.jpg\" -vcodec mjpeg -s " + this.width.ToString() + "x" + this.height.ToString() + " -y -r 30 \"" + str2 + "\"");
Process process = new Process();
processStartInfo.WorkingDirectory = Directory.GetCurrentDirectory();
processStartInfo.CreateNoWindow = true;
processStartInfo.UseShellExecute = false;
processStartInfo.RedirectStandardError = true;
process.StartInfo = processStartInfo;
process.Start();
StreamReader standardError = process.StandardError;
Trace.WriteLine(standardError.ReadToEnd());
standardError.Close();
process.WaitForExit();
return process.ExitCode != 1 && process.ExitCode != -1;
}
catch (Exception ex)
{
Trace.WriteLine("CreateVideo: " + ex.Message);
return false;
}
finally
{
if (bitmap != null)
bitmap.Dispose();
try
{
if (Directory.Exists(this.outputFolder + "\\temp"))
Directory.Delete(this.outputFolder + "\\temp", true);
}
catch
{
}
}
}
Get Audio Length
public int GetAudioLength(string path)
{
string output = this.GetOutput(path);
int num = 0;
if (output == "" || output.Contains("Invalid data found when processing input") || output.Contains("could not find codec parameters"))
return num;
string str;
try
{
str = Regex.Match(output, "(?:Duration\\:)(.*?)(?:,)", RegexOptions.Singleline).Groups[1].Value.Trim();
}
catch (Exception ex)
{
str = "";
}
if (str != "")
{
try
{
num = int.Parse(str.Split(':')[0]) * 3600;
num += int.Parse(str.Split(':')[1]) * 60;
num += (int)double.Parse(str.Split(':')[2]);
}
catch (Exception ex)
{
}
}
return num;
}
Get Output
private string GetOutput(string video_file)
{
try
{
return Process.Start(new ProcessStartInfo()
{
FileName = Environment.CurrentDirectory + "\\sm\\ffmpeg.exe",
Arguments = "-i \"" + video_file + "\"",
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden
}).StandardError.ReadToEnd();
}
catch (Exception ex)
{
return "";
}
}
I've looked around but couldn't find a solution. Any help will be greatly appreciated.

Related

C# is unable to create a process and call a R script by that process

My c# code
public static string RunRScript(string filePath, string rScriptExecutablePath, string args, int totalFiles,
int RowsInChunk, int TotalRows, string identity)
{
string rCodeFilePath = filePath; //RScriptPath.GetFilePath();
//string file = rCodeFilePath;
string result = string.Empty;
// IEnumerable<string> connections = _connections.GetConnections(identity)
try
{
var info = new ProcessStartInfo();
info.FileName = rScriptExecutablePath;
info.WorkingDirectory = Path.GetDirectoryName(rScriptExecutablePath);
info.Arguments = "\"" + rCodeFilePath + "\"" + " " + args;
info.RedirectStandardInput = false;
info.RedirectStandardOutput = true;
info.UseShellExecute = false;
info.CreateNoWindow = true;
string fileName = string.Empty;
DateTime startTime = DateTime.Now;
List<ProgressTracker> lstProgress = new List<ProgressTracker>();
ProgressTracker p;
using (var proc = new Process())
{
//proc.StartInfo.Verb = "runas";
for (int i = 1; i <= totalFiles; i++)
{
p = new ProgressTracker();
p.DT = DateTime.Now;
p.Progress = i;
lstProgress.Add(p);
info.Arguments = "\"" + rCodeFilePath + "\"" + " " + args + " " + i.ToString();
proc.StartInfo = info;
proc.Start();
proc.WaitForExit();
result = proc.StandardOutput.ReadToEnd();
p.TimeTaken = (DateTime.Now - p.DT).TotalSeconds;
Functions.SendProgress("Process in progress...", i, totalFiles, RowsInChunk, TotalRows, lstProgress, identity);
}
}
return FormatOutput(result);
}
catch (Exception ex)
{
throw new Exception("R Script failed: " + result, ex);
}
}
Now objects have values like
info.FileName = C:\Program Files\R\R-3.4.3\bin\Rscript.exe
info.WorkingDirectory = C:\Program Files\R\R-3.4.3\bin
info.Arguments = "C:\MANOJ R\Topic modelling v2\TM_Webapi\Honeywell.UOP.TopicModel.Api\Uploads\h481821\TopicSearch.R" h481821 1
But process is not creating and its not calling R script and even it doesn't throwing any exception
Even I tried running VS as admin but no luck!
I have changed the .exe file path from
C:\Program Files\R\R-3.4.3\bin\Rscript.exe
to
C:\Program Files\R\R-3.4.3\bin\x64\Rscript.exe
Since I am using 64 bit machine
Now the process is working

c# generate hocr file using charlesw tesseract

how can i generate hocr using the tesseract wrapper here
currently i need to dynamically add the location of the tessdata to the environment variables and run my code
System.Diagnostics.Process pProcess = new System.Diagnostics.Process();
pProcess.StartInfo.FileName = System.IO.Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]) + #"\tesseract-3.05.00dev-win32-vc19\tesseract.exe";
string inputImg = #"00067.jpg";
string hocrLocation = #"00067";
string argsPdf = "\"" + inputImg + "\"" + " " + "\"" + hocrLocation + "\"" + " hocr ";
Console.WriteLine(argsPdf);
pProcess.StartInfo.Arguments = argsPdf;
pProcess.StartInfo.CreateNoWindow = false;
pProcess.StartInfo.UseShellExecute = false;
pProcess.StartInfo.RedirectStandardOutput = true;
pProcess.Start();
string strOutput = pProcess.StandardOutput.ReadToEnd();
Console.WriteLine("OUtput: " + strOutput);
pProcess.WaitForExit();
and then i found the tesseract wrapper. how can i generate an hocr file using the wrapper? i cant find an example how to do it.
this is the current code(from the example ) im using but how to output an hocr file?
var testImagePath = "./phototest.tif";
if (args.Length > 0)
{
testImagePath = args[0];
}
try
{
using (var engine = new TesseractEngine(#"./tessdata", "eng", EngineMode.Default))
{
using (var img = Pix.LoadFromFile(testImagePath))
{
using (var page = engine.Process(img))
{
}
}
}
}
catch (Exception e)
{
Trace.TraceError(e.ToString());
Console.WriteLine("Unexpected Error: " + e.Message);
Console.WriteLine("Details: ");
Console.WriteLine(e.ToString());
}
string hocrText = page.GetHOCRText(pageNum - 1);

Images in HTML not displaying in PDF in WKHTMLTOPDF

Hi am using Wkhtmltopdf to create PDF from Html page using c#, Asp.net. PDF are created smoothly, but when I add images to HTML it does not get displayed on PDF.
<div id="Image" class="right" style="background:#333;height:15%;width:25%;">
<img width="100%" height="100%" src="../TempLogo/chafa.jpg" />
I have used "file:///E:/AMS/AMS/AMS.WEB/TempLogo/chafa.jpg" & "src="localhost:5822/AMS.WEB/TempLogo/chafa.jpg"; also but it does not work. I also tried to change Version from 0.11 to 0.9 but it also not succeed
public static string HtmlToPdf(string pdfOutputLocation, string outputFilenamePrefix, string[] urls,
string[] options = null,
// string pdfHtmlToPdfExePath = "C:\\Program Files (x86)\\wkhtmltopdf\\wkhtmltopdf.exe")
string pdfHtmlToPdfExePath = "C:\\Program Files\\wkhtmltopdf\\wkhtmltopdf.exe")
{
string urlsSeparatedBySpaces = string.Empty;
try
{
//Determine inputs
if ((urls == null) || (urls.Length == 0))
throw new Exception("No input URLs provided for HtmlToPdf");
else
urlsSeparatedBySpaces = String.Join(" ", urls); //Concatenate URLs
string outputFolder = pdfOutputLocation;
string outputFilename = outputFilenamePrefix + "_" + DateTime.Now.ToString("yyyy-MM-dd-hh-mm-ss-fff") + ".PDF"; // assemble destination PDF file name
var p = new System.Diagnostics.Process()
{
StartInfo =
{
FileName = pdfHtmlToPdfExePath,
Arguments = ((options == null) ? "" : String.Join(" ", options)) + " " + urlsSeparatedBySpaces + " " + outputFilename,
UseShellExecute = false, // needs to be false in order to redirect output
RedirectStandardOutput = true,
RedirectStandardError = true,
RedirectStandardInput = true, // redirect all 3, as it should be all 3 or none
WorkingDirectory = HttpContext.Current.Server.MapPath(outputFolder),
CreateNoWindow = true
}
};
p.Start();
// read the output here...
var output = p.StandardOutput.ReadToEnd();
var errorOutput = p.StandardError.ReadToEnd();
// ...then wait n milliseconds for exit (as after exit, it can't read the output)
p.WaitForExit(60000);
// read the exit code, close process
int returnCode = p.ExitCode;
p.Close();
// if 0 or 2, it worked so return path of pdf
if ((returnCode == 0) || (returnCode == 2))
return outputFolder + outputFilename;
else
throw new Exception(errorOutput);
}
catch (Exception exc)
{
throw new Exception("Problem generating PDF from HTML, URLs: " + urlsSeparatedBySpaces + ", outputFilename: " + outputFilenamePrefix, exc);
}
}

Executing UninstallString using C#

I have a problem to execute uninstallString using process, it won't work in all cases.
I need a generic procedure that will run in any case.
one of my ideas was to parse uninstall string
Code:
int indexOfExe = uninstallString.ToLower().IndexOf(".exe") + 4;
string exeFile = uninstallString.Substring(0, indexOfExe).Trim();
string args = uninstallString.Substring(indexOfExe, uninstallString.Length - indexOfExe).Trim();
if (args.Length > 0)
{
procStartInfo.FileName = exeFile;
procStartInfo.Arguments = args;
}
else
{
procStartInfo.FileName = exeFile;
procStartInfo.Arguments = "";
}
procStartInfo.Verb = "runas";
procStartInfo.CreateNoWindow = true;
procStartInfo.UseShellExecute = false ;
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo = procStartInfo;
proc.Start();
proc.WaitForExit();
my second idea was:
Code:
if (uninstallString.Contains("msiexec"))
{
uninstallString = uninstallString.Replace("\"", "");
uninstallString = RegistryHandler.getCommandInCommaAndArgumentsOutside(uninstallString);
}
else
{
procStartInfo.FileName = "cmd";
string[] words = uninstallString.Split("/".ToCharArray());
if (uninstallString.StartsWith(#"""") && words.Count() == 1)
{
procStartInfo.FileName = uninstallString;
procStartInfo.Arguments = "";
}
else
{
//procStartInfo.Arguments = "/c " + "\"" + uninstallString + "\"";
if ((uninstallString.StartsWith(#"""") && words.Count() > 1))
{
procStartInfo.Arguments = "/c " + uninstallString;
}
else
{
procStartInfo.Arguments = "/c " + RegistryHandler.getCommandInCommaAndArgumentsOutsideByExe(uninstallString);
}
}
}
but still it won't cover all cases.
What is the generic solution for all cases?
Your second idea should, technically, work (for all programs using Windows Installer). However, you need to get the proper uninstall string. I suspect the problem is your Uninstall String is incorrect.
You should be able to query the registry for the Uninstall String by looking at:
HKLM\Software\Microsoft\Windows\Currentversion\Uninstall\{NameOfApplication}\UninstallString
The section above marked {NameOfApplication} should have an entry for all programs which can be uninstalled. For details, see the Uninstall Registry Key.
//i wrote this code, which is working in most of the cases :
//----------------------------------------------------------------------------------------------
if (uninstallString.Contains("msiexec"))
{
uninstallString = uninstallString.Replace("\"", "");
uninstallString = RegistryHandler.getCommandInCommaAndArgumentsOutside(uninstallString);
}
else
{
if (uninstallString.StartsWith(#""""))
{
int indexOfLastComma = uninstallString.IndexOf("\"", 1) + 1;
procStartInfo.FileName = uninstallString.Substring(0, indexOfLastComma);
procStartInfo.Arguments = uninstallString.Substrin(indexOfLastComma,uninstallString.Length - indexOfLastComma));
}
else
{
procStartInfo.FileName = "cmd.exe";
procStartInfo.Arguments = "/c " + RegistryHandler.getCommandInCommaAndArgumentsOutsideByExe(uninstallString);
}
}
//----------------------------------------------------------------------------------------------
public static string getCommandInCommaAndArgumentsOutsideByExe(string command)
{
int ind = 0;
string[] prms = command.Split(' ');
ind = prms[0].Length; //command.IndexOf(".exe") + 4;
int exeLocationIndex = command.IndexOf(".exe") + 4;
string cmd = command.Substring(0, exeLocationIndex);
string arguments = command.Substring(command.IndexOf(".exe") + 4, command.Length - exeLocationIndex);
return "\"" + cmd + "\"" + arguments;
}
Here is my code, using the same way as Roy did,perhaps a litter simpler:
private string SwitchCondition(string uninstallstring)
{
if (uninstallstring.Substring(0, 1).Equals("\"") |
uninstallstring.ToLower().Contains("msiexec") |
uninstallstring.Contains("~"))
{
Debug.WriteLine(uninstallstring);
}
else if (uninstallstring.ToLower().IndexOf(".exe") > 0)
{
uninstallstring = "\"" + uninstallstring.Insert(uninstallstring.ToLower().IndexOf(".exe") + 4, "\"");
Debug.WriteLine("Contains .exe" + uninstallstring);
}
else
{
uninstallstring = "\"" + uninstallstring + "\"";
Debug.WriteLine("Case end " + uninstallstring);
}
return uninstallstring;
}

How to get the video duration using FFMPEG in C# asp.net

I want to get the video file duration in string using C#. I searched the internet and all i get is:
ffmpeg -i inputfile.avi
And every1 say that parse the output for duration.
Here is my code which is
string filargs = "-y -i " + inputavi + " -ar 22050 " + outputflv;
Process proc;
proc = new Process();
proc.StartInfo.FileName = spath;
proc.StartInfo.Arguments = filargs;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.CreateNoWindow = false;
proc.StartInfo.RedirectStandardOutput = false;
try
{
proc.Start();
}
catch (Exception ex)
{
Response.Write(ex.Message);
}
try
{
proc.WaitForExit(50 * 1000);
}
catch (Exception ex)
{ }
finally
{
proc.Close();
}
Now please tell me how can i save the output string and parse it for the video duration.
Thanks and regards,
There is another Option to get Video Length ,by using Media Info DLL
Using Ffmpeg :
proc.StartInfo.RedirectErrorOutput = true;
string message = proc.ErrorOutput.ReadToEnd();
Filtering shouldn't be an issue ,so do it you're self.
PS : using ffmpeg you should not read the StandardOutput but ErrorOutput i dont know why ,but it work's only like that.
FFmpeg is a little bit of an adventure to parse. But in any case, here's what you need to know.
First, FFmpeg doesn't play well with RedirectOutput options
What you'll need to do is instead of launching ffmpeg directly, launch cmd.exe, passing in ffmpeg as an argument, and redirecting the output to a "monitor file" through a command line output like so... note that in the while (!proc.HasExited) loop you can read this file for real-time FFmpeg status, or just read it at the end if this is a quick operation.
FileInfo monitorFile = new FileInfo(Path.Combine(ffMpegExe.Directory.FullName, "FFMpegMonitor_" + Guid.NewGuid().ToString() + ".txt"));
string ffmpegpath = Environment.SystemDirectory + "\\cmd.exe";
string ffmpegargs = "/C " + ffMpegExe.FullName + " " + encodeArgs + " 2>" + monitorFile.FullName;
string fullTestCmd = ffmpegpath + " " + ffmpegargs;
ProcessStartInfo psi = new ProcessStartInfo(ffmpegpath, ffmpegargs);
psi.WorkingDirectory = ffMpegExe.Directory.FullName;
psi.CreateNoWindow = true;
psi.UseShellExecute = false;
psi.Verb = "runas";
var proc = Process.Start(psi);
while (!proc.HasExited)
{
System.Threading.Thread.Sleep(1000);
}
string encodeLog = System.IO.File.ReadAllText(monitorFile.FullName);
Great, now you've got the log of what FFmpeg just spit out. Now to get the duration. The duration line will look something like this:
Duration: 00:10:53.79, start: 0.000000, bitrate: 9963 kb/s
Clean up the results into a List<string>:
var encodingLines = encodeLog.Split(System.Environment.NewLine[0]).Where(line => string.IsNullOrWhiteSpace(line) == false && string.IsNullOrEmpty(line.Trim()) == false).Select(s => s.Trim()).ToList();
... then loop through them looking for Duration.
foreach (var line in encodingLines)
{
// Duration: 00:10:53.79, start: 0.000000, bitrate: 9963 kb/s
if (line.StartsWith("Duration"))
{
var duration = ParseDurationLine(line);
}
}
Here's some code that can do the parse for you:
private TimeSpan ParseDurationLine(string line)
{
var itemsOfData = line.Split(" "[0], "="[0]).Where(s => string.IsNullOrEmpty(s) == false).Select(s => s.Trim().Replace("=", string.Empty).Replace(",", string.Empty)).ToList();
string duration = GetValueFromItemData(itemsOfData, "Duration:");
return TimeSpan.Parse(duration);
}
private string GetValueFromItemData(List<string> items, string targetKey)
{
var key = items.FirstOrDefault(i => i.ToUpper() == targetKey.ToUpper());
if (key == null) { return null; }
var idx = items.IndexOf(key);
var valueIdx = idx + 1;
if (valueIdx >= items.Count)
{
return null;
}
return items[valueIdx];
}
Just check it out::
//Create varriables
string ffMPEG = System.IO.Path.Combine(Application.StartupPath, "ffMPEG.exe");
system.Diagnostics.Process mProcess = null;
System.IO.StreamReader SROutput = null;
string outPut = "";
string filepath = "D:\\source.mp4";
string param = string.Format("-i \"{0}\"", filepath);
System.Diagnostics.ProcessStartInfo oInfo = null;
System.Text.RegularExpressions.Regex re = null;
System.Text.RegularExpressions.Match m = null;
TimeSpan Duration = null;
//Get ready with ProcessStartInfo
oInfo = new System.Diagnostics.ProcessStartInfo(ffMPEG, param);
oInfo.CreateNoWindow = true;
//ffMPEG uses StandardError for its output.
oInfo.RedirectStandardError = true;
oInfo.WindowStyle = ProcessWindowStyle.Hidden;
oInfo.UseShellExecute = false;
// Lets start the process
mProcess = System.Diagnostics.Process.Start(oInfo);
// Divert output
SROutput = mProcess.StandardError;
// Read all
outPut = SROutput.ReadToEnd();
// Please donot forget to call WaitForExit() after calling SROutput.ReadToEnd
mProcess.WaitForExit();
mProcess.Close();
mProcess.Dispose();
SROutput.Close();
SROutput.Dispose();
//get duration
re = new System.Text.RegularExpressions.Regex("[D|d]uration:.((\\d|:|\\.)*)");
m = re.Match(outPut);
if (m.Success) {
//Means the output has cantained the string "Duration"
string temp = m.Groups(1).Value;
string[] timepieces = temp.Split(new char[] {':', '.'});
if (timepieces.Length == 4) {
// Store duration
Duration = new TimeSpan(0, Convert.ToInt16(timepieces[0]), Convert.ToInt16(timepieces[1]), Convert.ToInt16(timepieces[2]), Convert.ToInt16(timepieces[3]));
}
}
With thanks,
Gouranga Das.

Categories

Resources