I need to convert files from AWS cloud, which mounted like a local drive by using TntDrive.
I tried to use FFMpegConverter.ConvertMedia method, but it works slow. In another question someone explained to me next:
"It looks like you need to use the FFMpegConverter.ConvertLiveMedia method instead of the FFMpegConverter.ConvertMedia method to achieve this. Overall you will still find that you will be probably I/O bound rather than CPU bound."
But next code didn't work for me:
static void Main(string[] args)
{
string input_path =
#"D:\WAV\ALBUM1\UNDER_ALBUM1\APOV01_10 POV 8_MAIN.WAV";
string dest_path = #"D:\result.mp3";
using (FileStream inputStream = new FileStream(input_path, FileMode.Open))
{
var converter = new FFMpegConverter();
var result = converter.ConvertLiveMedia(
inputStream, "WAV",
dest_path, "MP3",
new ConvertSettings
{
AudioSampleRate = 44100,
CustomOutputArgs = " -b:a 192k "
}
);
Console.ReadLine();
}
}
What's wrong with my code ?
var ffMpeg = new FFMpegConverter();
ffMpeg.ConvertMedia(input_path, null, dest_path, "mp3", new ConvertSettings() {
CustomOutputArgs = " -b:a 192k -ar 44100 -y -f mp3 -movflags faststart"
});
You have to start the conversion I think...
result.Start();
Related
I am currently working on a discord bot that is able to play a song using soundcloud.
Unfortunately, I can't seem to figure out how to get it to read from the url and stream it!
The bot it made in C#, and uses Discord.net library and ffmpeg for the audio.
Would love to hear some suggestions!
These are the three functions involved:
[Command("teste", RunMode = RunMode.Async)]
public async Task Play(IVoiceChannel channel = null)
{
var audioClient = await JoinChannel(channel);
var url = "https://soundcloud.com/campatechlive/campatech-live-feat-
matheus-moussa-arabian-system-vol-2-psy-trance-150-original-mix";
var ffmpeg = new Ffmpeg(audioClient);
await ffmpeg.SendAsync(url);
}
public async Task SendAsync(string path)
{
using (var ffmpeg = CreateStream(path))
using (var output = ffmpeg.StandardOutput.BaseStream)
using (var discord = _client.CreatePCMStream(AudioApplication.Mixed))
{
try { await output.CopyToAsync(discord); }
finally { await discord.FlushAsync(); }
}
}
private Process? CreateStream(string path)
{
return Process.Start(new ProcessStartInfo
{
FileName = "ffmpeg",
Arguments = $"-hide_banner -loglevel panic -i \"{path}\" -ac 2 -f
s16le -ar 48000 pipe:1",
UseShellExecute = false,
RedirectStandardOutput = true,
});
}
I'm guessing it's something on the ffmpeg arguments, but can't kind of figure out what.
I've tried a bunch of different arguments on ffmpeg, but none of them worked.
Anyone can lend me a hand?
I am currently working on a utility that is responsible for pulling audio and video files from the cloud and merging them together via FFMPEG. As I am new to FFMPEG, I am going to split the question into an FFMPEG part and a C# part just so people can answer either 1 part or the other (or both!).
FFMPEG Part
Currently, I have a working FFMPEG arg if there is only 1 video file present and it needs to be merged with multiple files.
ffmpeg -i input1.mkv -i input1.mka -i input2.mka -i input3.mka -i input4.mka -filter_complex "[1:a]adelay=0s:all=1[a1pad];[2:a]adelay=20s:all=1[a2pad];[3:a]adelay=30s:all=1[a3pad];[4:a]adelay=40s:all=1[a4pad];[a1pad][a2pad][a3pad][a4pad]amix=inputs=4:weights=1|1|1|1[aout]" -map [aout] -map 0:0 output4.mkv
The delays you see in there are determined by subtracting the start time of each file from the start time of the earliest created audio or video file. I know that if I wanted to create a horizontal stack of multiple videos, i could just do
ffmpeg -i input1.mkv -i input1.mka -i input2.mkv -i input2.mka -i input3.mka -i input4.mka
-filter_complex
"[2:v]tpad=start_duration=120:color=black[vpad];
[3:a]adelay=120000:all=1[a2pad];
[4:a]adelay=180000:all=1[a3pad];
[5:a]adelay=200000:all=1[a4pad];
[0:v][vpad]hstack=inputs=2[vout];
[1:a][a2pad][a3pad][a4pad]amix=inputs=4:weights=1|1|1|1[aout]"
-map [vout] -map [aout]
output.mkv
but what I want to do is both keep those delays for the audio and video files AND concatenate (not stack) those videos, how would i go about doing that?
C# Part
You see that giant arg up there? The utility is supposed to generate that based on a List of recordings. Here is the model.
List<FileModel> _records;
public class FileModel {
public string Id { get; set; }
public string FileType { get; set; }
public string StartTime { get; set; }
}
The utility has to then go through that list and create the arg (as seen in the FFMPEG part) to be executed by the Xabe.FFMPEG package. The way i was thinking to approach this is to basically create 2 string builders. 1 string builder will be responsible for dealing with the inputs, the other string builder. Here is what i have so far
private async Task CombineAsync()
{
var minTime = _records.Min(y => Convert.ToDateTime(y.StartTime));
var frontBuilder = new StringBuilder("-y ");
var middleBuilder = new StringBuilder("-filter_complex \"");
var endString = $" -map [vout] -map [aout] {_folderPath}\\CombinedOutput.mkv";
for (var i = 0; i < _records.Count; i++)
{
var type = _records[i].FileType.ToLower();
var delay = (Convert.ToDateTime(_records[i].StartTime).Subtract(minTime)).TotalSeconds;
frontBuilder.Append($"-i {_folderPath + "\\" + _records[i].Id} ");
var addColon = i != _records.Count - 1 ? ";" : "";
middleBuilder.Append(type.Equals("video") ? $"[{i}:v]tpad=start_duration={delay}:color=black[v{i}pad]{addColon} " : $"[{i}:a]adelay={delay}s:all=1[a{i}pad]{addColon} ");
}
middleBuilder.Append("\"");
Console.WriteLine(frontBuilder.ToString() + middleBuilder.ToString() + endString);
// var args = frontBuilder + middleBuilder + endString;
// try
// {
// var conversionResult = await FFmpeg.Conversions.New().Start(args);
// Console.WriteLine(JsonConvert.SerializeObject(conversionResult));
// }
// catch (Exception e)
// {
// Console.WriteLine(e);
// }
}
Is this the correct way to go about building the argument out?
How in god's name do i get something like this in there, since it relies on naming and total count for the piping and inputs=
[0:v][vpad]hstack=inputs=2[vout]; // This part will change for video concatenation depending on what gets answered above
[1:a][a2pad][a3pad][a4pad]amix=inputs=4:weights=1|1|1|1[aout]
In amix document
Note that this filter only supports float samples(the amerge and pan audio filters support many formats).
Maybe your files is many format, try amerge
For easy generate arguments with so much filters, try FFmpegArgs
FFmpegArg ffmpegArg = new FFmpegArg().OverWriteOutput();
List<ImageMap> imageMaps = new List<ImageMap>();
List<AudioMap> audioMaps = new List<AudioMap>();
foreach (var item in _records)
{
if (item.IsVideo)
{
imageMaps.Add(ffmpegArg.AddImageInput(new ImageFileInput(item.FilePath))
.TpadFilter().StartDuration(item.Delay).MapOut);
}
else
{
audioMaps.Add(ffmpegArg.AddAudioInput(new AudioFileInput(item.FilePath))
.AdelayFilter().Delays(item.Delay).All(true).MapOut);
}
}
var imageMap = imageMaps.HstackFilter().MapOut;
var audioMap = audioMaps.AmergeFilter().MapOut;
ffmpegArg.AddOutput(new VideoFileOutput("out.mp4", imageMap, audioMap));
var result = ffmpegArg
.Render(c => c
.WithFFmpegBinaryPath("path to ffmpeg.exe")
.WithWorkingDirectory("working dir"))
.Execute();
result.EnsureSuccess();
Or by kesh comment
FFmpegArg ffmpegArg = new FFmpegArg().OverWriteOutput();
List<ImageMap> imageMaps = new List<ImageMap>();
List<AudioMap> audioMaps = new List<AudioMap>();
foreach (var item in _records)
{
if (item.IsVideo)
{
imageMaps.Add(ffmpegArg.AddImageInput(new ImageFileInput(item.FilePath))
.TpadFilter().StartDuration(item.Delay).MapOut);
}
else
{
audioMaps.Add(ffmpegArg.AddAudioInput(new AudioFileInput(item.FilePath)));
//audioMaps.Add(ffmpegArg.AddAudioInput(new AudioFileInput(item.FilePath).SsPosition(item.Skip)));
}
}
var imageMap = imageMaps.HstackFilter().MapOut;
var concatFilter = audioMaps.Select(x => new ConcatGroup(x)).ConcatFilter();
ffmpegArg.AddOutput(new VideoFileOutput("out.mp4", imageMap, concatFilter.AudioMapsOut.First()));
var result = ffmpegArg
.Render(c => c
.WithFFmpegBinaryPath("path to ffmpeg.exe")
.WithWorkingDirectory("working dir"))
.Execute();
result.EnsureSuccess();
When trying to use stdin and stdout in C# (Unity) to pipe to a Python process, I get about a dozen or so transactions and the process breaks and the error "ObjectDisposedException: The object was used after being disposed."
After trying several of the more obvious things, I'm bringing the problem here perhaps someone know just the right technique. Thanks in advance.
Here's the C# Startup code:
Process pyProcess; // <=== fixed
ProcessStartInfo pyStartInfo;
public StreamReader pyStreamReader;
public StreamWriter pyStreamWriter;
public void startPython()
{
// Create new process start info
pyStartInfo = new ProcessStartInfo(pyPath)
{
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardOutput = true,
Arguments = pyApp + " " + pyArgs
};
pyProcess = new Process { StartInfo = pyStartInfo };
pyProcess.Start();
pyStreamReader = pyProcess.StandardOutput;
pyStreamWriter = pyProcess.StandardInput;
pyStreamWriter.WriteLine("Hello!");
string str = pyStreamReader.ReadLine();
Debug.LogFormat(str + "\n");
}
void Start()
{
if(testPython == true)
startPython();
Here is the fragment that generates data sent to python at each update...
if (controller.testPython)
{
string str, python;
str = String.Format("data to send");
pyStreamWriter.DiscardBufferedData(); #<==== fixed
pyStreamWriter.WriteLine(str);
python = pyStreamReader.ReadLine();
Debug.LogFormat("python says: " + python + "\n");
}
And here is the simplified python process that's echoing the data
while True:
cmd = input() # read a command from c#
print(cmd) # process the cmd, here we just echo it back to c#
After a little experimentation, I discovered that adding
pyStreamReader.DiscardBufferedData();
before
pyStreamWriter.WriteLine(str);
solves the main problem and this simple form of piping seems to work, at least for hundreds of transactions that I observed.
I also had to declare pyProcess outside the scope so the code so that its handle is not released. That resolved the ObjectDisposed exception.
I want to extract first frame of uploaded video and save it as image file.
Possible video formats are mpeg, avi and wmv.
One more thing to consider is that we are creating an ASP.NET website.
You could use FFMPEG as a separate process (simplest way) and let it decode first IDR for you. Here you have a class FFMPEG that has GetThumbnail() method, to it you pass address of video file, address of the JPEG image to be made, and resolution that you want the image to be:
using System.Diagnostics;
using System.Threading;
public class FFMPEG
{
Process ffmpeg;
public void exec(string input, string output, string parametri)
{
ffmpeg = new Process();
ffmpeg.StartInfo.Arguments = " -i " + input+ (parametri != null? " "+parametri:"")+" "+output;
ffmpeg.StartInfo.FileName = "utils/ffmpeg.exe";
ffmpeg.StartInfo.UseShellExecute = false;
ffmpeg.StartInfo.RedirectStandardOutput = true;
ffmpeg.StartInfo.RedirectStandardError = true;
ffmpeg.StartInfo.CreateNoWindow = true;
ffmpeg.Start();
ffmpeg.WaitForExit();
ffmpeg.Close();
}
public void GetThumbnail(string video, string jpg, string velicina)
{
if (velicina == null) velicina = "640x480";
exec(video, jpg, "-s "+velicina);
}
}
Use like this:
FFMPEG f = new FFMPEG();
f.GetThumbnail("videos/myvid.wmv", "images/thumb.jpg", "1200x223");
For this to work, you must have ffmpeg.exe in folder /utils, or change the code to locate ffmpeg.exe.
There are other ways to use FFMPEG in .NET, like .NET wrappers, you could google for them. They basically do the same thing here, only better. So if FFMPEG gets your job done, I'd recomend to use .NET wrapper.
Try to make argument string format like:
ffmpeg.StartInfo.Arguments =" -i c:\MyPath\MyVideo -vframes 1 c:\MyOutputPath\MyImage%d.jpg"
Instead of
ffmpeg.StartInfo.Arguments = " -i " + input+ (parametri != null? " "+parametri:"")+" "+output;
in the answer code provided above.
I don't know what was the reason, but second mentioned argument line is not working on my machine whereas when I changed argument like the first command it works fine.
Probably the best tool for working with videos programatically is FFMpeg. It has support for many formats, even wmv. I suspect there's even a .net wrapper for it.
I need a way to take screenshots of my functional tests. Right now I'm using Selenium 2 with C# bindings. I pretty much want to take a screenshot at the end of the test to make sure the desired page is displayed. Are there any particular tools you guys know of that I can incorporate into my C# code that will trigger a screenshot? I couldn't find a built-in Selenium 2 solution (without looking it over).
To do screenshots in Selenium 2 you need to do the following
driver = new FireFoxDriver(); // Should work in other Browser Drivers
driver.Navigate().GoToUrl("http://www.theautomatedtester.co.uk");
Screenshot ss = ((ITakesScreenshot) driver).GetScreenshot();
//Use it as you want now
string screenshot = ss.AsBase64EncodedString;
byte[] screenshotAsByteArray = ss.AsByteArray;
ss.SaveAsFile("filename", ImageFormat.Png); //use any of the built in image formating
ss.ToString();//same as string screenshot = ss.AsBase64EncodedString;
That code should work, as I quickly tested it in IronPython Repl. See the IronPython code below
import clr
clr.AddReference("WebDriver.Common.dll")
clr.AddReference("WebDriver.Firefox.dll")
from OpenQA.Selenium import *
from OpenQA.Selenium.Firefox import *
driver = FirefoxDriver()
driver.Navigate().GoToUrl("http://www.theautomatedtester.co.uk")
s = driver.GetScreenshot()
s.AsBaseEncodedString
# HUGE string appears in the REPL
var driver = new InternetExplorerDriver();
driver.Navigate().GoToUrl("http://www.google.com");
var ss = driver.GetScreenshot();
ss.SaveAsFile("ss.png", System.Drawing.Imaging.ImageFormat.Png);
I don't know if it matters, but I ended up having to cast the driver when i was writing in c#.
something like:
Screenshot ss = ((ITakesScreenshot)driver).GetScreenshot();
Just use the extension method TakeScreenshot() in one line of code.
IWebDriver driver = new InternetExplorerDriver();
driver.Navigate().GoToUrl("Your_Homepage_Url");
driver.TakeScreenshot().SaveAsFile("file_name_string", ImageFormat.Jpeg);
Add a reference of System.Drawing in your solution/project.
Use System.Drawing.Imaging namespace in your test.
Here I am capturing the screen shot of Facebook Home page.
using System;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support.UI;
using NUnit.Framework;
using System.IO;
using System.Collections;
using System.Drawing.Imaging;
namespace FacebookRegistrationUsingC_Sharp
{
[TestFixture]
public class ScreenShot
{
IWebDriver driver = null;
IWebElement element = null;
[SetUp]
public void SetUp()
{
driver = new ChromeDriver("G:\\Selenium_Csharp\\Jar\\chromedriver_win32");
driver.Navigate().GoToUrl("https://www.Facebook.com");
driver.Manage().Window.Maximize();
}
[Test]
public void TestScreenShot()
{
Screenshot ss = ((ITakesScreenshot)driver).GetScreenshot();
ss.SaveAsFile("e:\\pande", System.Drawing.Imaging.ImageFormat.Jpeg);
}
[TearDown]
public void TearDown()
{
driver = null;
element = null;
}
}
}
public void TakeScreenshot(string saveLocation) {
var location = GetPath() + _name + "\\" + saveLocation + ".png";
var ssdriver = _driver as ITakesScreenshot;
var screenshot = ssdriver.GetScreenshot();
screenshot.SaveAsFile(location, ImageFormat.Png);
}
This code will help you to take screen shot
JAVA
protected void fullPageScreenshot(String testname) {
String timeStamp = new SimpleDateFormat("dd_MM_yyyy_HH_mm_ss").format(Calendar.getInstance().getTime());
String imageName = testname + "-" + timeStamp + ".png";
Screenshot screenshot = new AShot().shootingStrategy(ShootingStrategies.viewportPasting(2000))
.takeScreenshot(DriverManager.getDriver());
try {
ImageIO.write(screenshot.getImage(), "PNG", new File("./FullPage_Screenshots/" + imageName));
} catch (Exception e) {
System.out.println("Capturing FullPage Screenshot failed");
}
}
use Ashot library to take fullpage screenshots - even where pages needs to be scrolled
https://mvnrepository.com/artifact/ru.yandex.qatools.ashot/ashot/1.5.4
Use System.Drawing.Imaging reference.
Following code can be used for taking screenshot.
IWebDriver driver = new FirefoxDriver();
ITakesScreenshot screenshotDriver = driver as ITakesScreenshot;
Screenshot screenshot = screenshotDriver.GetScreenshot();
String fp = "D:\\" + "snapshot" + "_"+ DateTime.Now.ToString("dd_MMMM_hh_mm_ss_tt") + ".png";
screenshot.SaveAsFile(fp, ImageFormat.Png);
Notes:
Timestamp has two advantages:
1) You'll get to know the perfect DateTime when screenshot is taken.
2) SaveAsFile function overwrites the existing file. So, DateTime can help for different file creation.
ScreenCaptureJob scj;
scj = new ScreenCaptureJob();
// Specify the path & file name in which you want to save
scj.OutputScreenCaptureFileName = #"C:\Users\jpavankumar\Desktop\Screencaptuere\ScreenRecording4.wmv";
// Start the Screen Capture Job
scj.Start(); scj.Stop();
Try this code out here ... hope it will be useful to you .... !
Define this in global code :
var counter = DateTime.Now.Ticks.ToString();
((ITakesScreenshot)driver).GetScreenshot().SaveAsFile((snap +counter + ".jpg").ToString(), OpenQA.Selenium.ScreenshotImageFormat.Jpeg);
test.Log(LogStatus.Fail, "Snapshot below: " + test.AddScreenCapture(snap + counter + ".jpg"));
driver.Url = "https://www.amazon.in/";
//Store image in bin folder
((ITakesScreenshot)driver).GetScreenshot().SaveAsFile("CurrentPage.png");
//Store image in D drive
((ITakesScreenshot)driver).GetScreenshot().SaveAsFile(#"D:\CurrentPage.png");
Best way to take screenshot and store in the file location in a generic way in python :
def screenShots(self):
fileName= NewFile + "." + str(round(time.time() * 1000)) + ".png"
screenshotDirectory = "../screenshot/" #Move to that directory where you want ot store the screenshot
relativeFileName = screenshotDirectory + fileName
currentDirectory = os.path.dirname(__file__)
destinationFile = os.path.join(currentDirectory,relativeFileName)
destinationDirectory = os.path.join(currentDirectory,screenshotDirectory)
try:
if not os.path.exists(destinationDirectory):
os.makedirs(destinationDirectory)
self.driver.save_screenshot(destinationFile)
self.log.info("Screenshot saved to directory" + destinationFile)
except:
self.log.error("Exception Occured")
print_stack()
Using selenium there were two calls I was familiar with: captureEntirePageScreenshot and captureScreenshot. You might want to look into those calls to see if they'll accomplish what you're after.