It takes to long to stop VlcMediaPlayer - libvlc

I have a simple WPF application. The application records an RTSP stream to a file. For this purpose Vlc.DotNet library is used.
I have tested the application with two computers and the results are the same for both.
The application code is given below.
public partial class MainWindow : Window
{
private IPath _pathWrapper;
private IDirectoryInfo _vlcLibDirectory;
private VlcMediaPlayer _videoRecorder;
public MainWindow()
{
InitializeComponent();
}
private void OnButtonClick(object sender, RoutedEventArgs e)
{
if (_videoRecorder != null && _videoRecorder.IsPlaying())
{
_videoRecorder.Stop();
Button.Background = Brushes.Blue;
_videoRecorder = null;
return;
}
string currentDirectory = AppDomain.CurrentDomain.BaseDirectory;
_pathWrapper = new PathWrap();
_vlcLibDirectory = new DirectoryInfoWrap(_pathWrapper.Combine(currentDirectory, "libvlc", IntPtr.Size == 4 ? "win-x86" : "win-x64"));
var options = new string[]
{
"--file-logging",
"--logfile=OnvifVideoRecording.log",
"-vvv"
};
_videoRecorder = new VlcMediaPlayer(_vlcLibDirectory.DirectoryInfo, options);
//string fileDestination = "\\\\\\BuildSrv\\Videos\\A, A, 1\\test.mp4";
string fileDestination = #"D:\Media\Video\A, A, 1\test.mp4";
if (File.Exists(fileDestination))
{
File.Delete(fileDestination);
}
string[] mediaOptions =
{
":sout=#file{dst='" + fileDestination + "'}",
":sout-keep"
};
_videoRecorder.SetMedia("rtsp://192.168.1.110:5504/channel=0,stream=0", mediaOptions);
_videoRecorder.Play();
Button.Background = Brushes.Red;
}
}
The application has a window. The window has a button. When this button is pressed for the first time, recording a video file is started and the button turns red. I usually record video files for 10 minutes. When the button is pressed for the second time, recording a video file is stopped and the button turns blue.
If I record a file to the local destination (to the same computer where the program is run, for example, D:\Media\Video\A, A, 1\test.mp4), everything is ok. Recording video file is started and stopped quickly, almost immediately.
The problems occur when I try to record a file to the remote computer (for example, \BuildSrv\Videos\A, A, 1\test.mp4). Recording a video file starts immediately. However, _videoRecorder.Stop() takes approximately 30 seconds – 1 minute. Resource monitor shows very high network use (90% in case of one computer and 100% in case of another) after the button is pressed for the second time (recording video is stopped). The longer the recorded video file is, the more time is needed to stop VlcMediaPlayer.
Why does stopping VlcMediaPlayer takes so much time in case of recording an RTSP stream to the remote computer? Can this problem be solved somehow?

Related

Codename One sound Media.play() memory leak?

My app uses some short sounds for user feedback. I use the following code:
private void playSound(String fileName) {
try {
FileSystemStorage fss = FileSystemStorage.getInstance();
String sep = fss.getFileSystemSeparator() + "";
String soundDir; // sounds must be in a directory
if (fss.getAppHomePath().endsWith(sep)) {
soundDir = fss.getAppHomePath() + "sounds"; // device
} else {
soundDir = fss.getAppHomePath() + sep + "sounds"; // simulator/windows
}
if (!fss.exists(soundDir)) {
// first time a sound is played: create directory
fss.mkdir(soundDir);
}
String filePath = soundDir + sep + fileName;
if (!fss.exists(filePath)) {
// first time this sound is played: copy from resources (place file in <project>/src)
InputStream is = Display.getInstance().getResourceAsStream(getClass(), "/" + fileName);
OutputStream os = fss.openOutputStream(filePath);
com.codename1.io.Util.copy(is, os);
}
Media media = MediaManager.createMedia(filePath, false);
//media.setVolume(100);
media.play();
} catch (IOException ex) {
log("Error playing " + fileName + " " + ex.getMessage());
}
}
Example call:
playSound("error.mp3");
This works fine on devices and in the simulator. However, if I do a long automatic test in the simulator (using Windows), playing a sound about every second,
this eats up all the RAM until Windows crashes. The Windows task manager, however, shows no exceptional memory usage of NetBeans and the Java process.
So my questions are: Is my code correct? Can this happen on devices too? Or else is there a way to prevent this in the simulator/Windows?
P.S.
I also tried the code from How to bundle sounds with Codename One?. That has the same problem and also
some sounds get lost (are not played).
I also tried the simple code from Codename One - Play a sound but that doesn't work.
We generally recommend keeping the Media instance for this sort of use case.
But if you can't just make sure to call cleanup when you're done:
MediaManager.addCompletionHandler(media, () -> media.cleanup());
media.play();

FileSystemWatcher not firing upon text file change and how to get appended lines into panel

I'm after some help or guidance if possible.
I'm trying to monitor a text file in real time and copy the appended text into panel within windows forms.
The text file is being updated via an exe file so it might be few lines appended in quick sessions or nothing for few minutes.
I have tried FileSystemWatcher but it does not seem to work which I cannot understand and also I'm very new to this event handlers etc and still learning in progress :(
private FileSystemWatcher watcher = new FileSystemWatcher();
public async void StandardOutputHandler(object sender, DataReceivedEventArgs outLine)
{
if (outLine.Data != null && !String.IsNullOrWhiteSpace(outLine.Data)) //checks if line coming from CMD is blank or empty
{
// check if cmd output was redirected into a log file
if (outLine.Data.Contains(">>"))
{
BeginInvoke(new MethodInvoker(() =>
{
//get log path and name
string[] commandLine = outLine.Data.Split('>');
this.logFileFullPath = commandLine[3];
this.logFileFullPath = this.logFileFullPath.Replace('"', ' ').Trim();
string[] split = logFileFullPath.Split('\\');
this.logFileName = split[6];
this.path = split[0] + "\\" + split[1] + "\\" + split[2] + "\\" + split[3] + "\\" + split[4] + "\\" + split[5];
//// Create a new FileSystemWatcher and set its properties.
watcher.Path = this.path + "\\";
watcher.Filter = this.logFileName;
//watch for changes to a a log file
watcher.NotifyFilter = (NotifyFilters.LastWrite | NotifyFilters.Size | NotifyFilters.LastAccess | NotifyFilters.CreationTime);
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.Created += new FileSystemEventHandler(OnChanged);
// Begin watching.
watcher.EnableRaisingEvents = true;
}));
}
}
// Define the event handlers.
private void OnChanged(object source, FileSystemEventArgs e)
{
MessageBox.Show("Im here");// not showing
//how to copy appended lines into panel??
}
The message box in OnChanged method is not coming up. I have manually amended the file or delete it and create it but the event is not being fired.
I believe this might be related to file being used by another process which in this case is an exe file updating it when necessary. Also, I think, the risk is that I might get only partial text if exe updates the log at the same time as I read the appended lines.
Is there a better way to monitor the text file updates and copy the content onto the panel within GUI application??
UPDATE:
I have moved the code into click event or initial method and it makes no difference. Message box is not appearing
public BatchRun()
{
InitializeComponent();
watcher.Path = "C:\\Test\\Projects\\99999\\Logs";
watcher.Filter = "*.log";
watcher.NotifyFilter = (NotifyFilters.LastWrite | NotifyFilters.Size | NotifyFilters.LastAccess | NotifyFilters.CreationTime);
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.Created += new FileSystemEventHandler(OnChanged);
watcher.EnableRaisingEvents = true;
}
It seems that you only begin watching the file in the call to StandardOutputHandler.
If this method is only called after writing to the file, then the watcher won't notice any changes to the file.
You probably want to have all the code in your MethodInvoker action somewhere it is called when the application starts (or at least when it needs to monitor the file).
Then in your OnChanged method you may have to invoke MessageBox.Show() on the UI thread.

ReceiveFromAsync leaking SocketAsyncEventArgs?

I have a client application that receives video stream from a server via UDP or TCP socket.
Originally, when it was written using .NET 2.0 the code was using BeginReceive/EndReceive and IAsyncResult.
The client displays each video in it's own window and also using it's own thread for communicating with the server.
However, since the client is supposed to be up for a long period of time, and there might be 64 video streams simultaneously, there is a "memory leak" of IAsyncResult objects that are allocated each time the data receive callback is called.
This causes the application eventually to run out of memory, because the GC can't handle releasing of the blocks in time. I verified this using VS 2010 Performance Analyzer.
So I modified the code to use SocketAsyncEventArgs and ReceiveFromAsync (UDP case).
However, I still see a growth in memory blocks at:
System.Net.Sockets.Socket.ReceiveFromAsync(class System.Net.Sockets.SocketAsyncEventArgs)
I've read all the samples and posts about implementing the code, and still no solution.
Here's how my code looks like:
// class data members
private byte[] m_Buffer = new byte[UInt16.MaxValue];
private SocketAsyncEventArgs m_ReadEventArgs = null;
private IPEndPoint m_EndPoint; // local endpoint from the caller
Initializing:
m_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
m_Socket.Bind(m_EndPoint);
m_Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, MAX_SOCKET_RECV_BUFFER);
//
// initalize the socket event args structure.
//
m_ReadEventArgs = new SocketAsyncEventArgs();
m_ReadEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(readEventArgs_Completed);
m_ReadEventArgs.SetBuffer(m_Buffer, 0, m_Buffer.Length);
m_ReadEventArgs.RemoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
m_ReadEventArgs.AcceptSocket = m_Socket;
Starting the read process:
bool waitForEvent = m_Socket.ReceiveFromAsync(m_ReadEventArgs);
if (!waitForEvent)
{
readEventArgs_Completed(this, m_ReadEventArgs);
}
Read completion handler:
private void readEventArgs_Completed(object sender, SocketAsyncEventArgs e)
{
if (e.BytesTransferred == 0 || e.SocketError != SocketError.Success)
{
//
// we got error on the socket or connection was closed
//
Close();
return;
}
try
{
// try to process a new video frame if enough data was read
base.ProcessPacket(m_Buffer, e.Offset, e.BytesTransferred);
}
catch (Exception ex)
{
// log and error
}
bool willRaiseEvent = m_Socket.ReceiveFromAsync(e);
if (!willRaiseEvent)
{
readEventArgs_Completed(this, e);
}
}
Basically the code works fine and I see the video streams perfectly, but this leak is a real pain.
Did I miss anything???
Many thanks!!!
Instead of recursively calling readEventArgs_Completed after !willRaiseEvent use goto to return to the top of the method. I noticed I was slowly chewing up stack space when I had a pattern similar to yours.

Windows Phone 7 Audio Recording Problem

I'm hoping someone can help me with this. I have found the examples for recording audio using XNA in a Silverlight application. And it works, however, only the first time in. I have all the recording functionality on a seperate WP7 Page and with successive visits to the page it doesn't work. The best I can tell is the microphone.start is getting called but the micophone.status remains stopped. What is weird is the BufferReady keeps getting called and the code within that function is all running but without the microphone really starting nothing is really happening. When you exit the app and come back in again the first time visit to the page and everything works fine, but a revisit to the page and it doesn't.
void microphone_BufferReady(object sender, EventArgs e)
{
this.Dispatcher.BeginInvoke(() =>
{
microphone.GetData(buffer);
stream.Write(buffer, 0, buffer.Length);
TimeSpan tsTemp = timer.Elapsed;
TextBlockSeconds.Text = tsTemp.Hours.ToString().PadLeft(2, '0') + ":" + tsTemp.Minutes.ToString().PadLeft(2, '0') + ":" + tsTemp.Seconds.ToString().PadLeft(2, '0');
if(timer.Elapsed.Seconds >5)
DoStop();
});
}
private void ButtonRecord_Click(object sender, RoutedEventArgs e)
{
DisableRecordButton();
timer = new Stopwatch();
timer.Start();
stream = new MemoryStream();
TextBlockSeconds.Text = "00:00:00";
TextBlockStatus.Text = "Recording: ";
microphone.BufferDuration = TimeSpan.FromMilliseconds(500);
buffer = new byte[microphone.GetSampleSizeInBytes(microphone.BufferDuration)];
microphone.BufferReady += new EventHandler<EventArgs>(microphone_BufferReady);
microphone.Start();
}
private void DoStop()
{
if (timer.IsRunning)
timer.Stop();
if (microphone.State == MicrophoneState.Started)
{
microphone.Stop();
TextBlockStatus.Text = "Stopped: Ready to save";
}
else
{
TextBlockStatus.Text = "Ready: ";
}
TextBlockSeconds.Text = string.Empty;
EnableRecordButton();
}
Update...
I found the problem but no solution. I was calling the microphone.stop via code on a timer (so I could limit the recorded audio to 5 seconds). Exact same code to execute when a manual stop button would be clicked. When clicking the manual stop button everything worked fine, could re-visit the page and all would be fine. When the stop was called in code from the timer, next visit to the page would not work. So I implemented it with only a manual stop button but really would have been nice to do it automatically (and to know what the real issue was).
actually when you are navigating away from the page you can add
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
this.MicroPhone.BufferReady -= this.Microphone_BufferReady;
}
and when you are returning to page add
this.MicroPhone.BufferReady += this.Microphone_BufferReady;
You can add this statement either in a page loaded event or an OnNavigatedTo event
Added string name = System.Threading.Thread.CurrentThread.ManagedThreadId.ToString() to make sure that it was on the same thread (and it was).
But finally worked this out, the problem is the microphone.stop doesn't stop the microphone from continuing to fire the buffer ready event (like I was expecting). And it would seem the way the page is cached this causes some weird problems with that event still firing. So I added the code
microphone.BufferReady -= new EventHandler<EventArgs>(microphone_BufferReady);
to my code for stopping, and it all works now.
I can't see from your code how you're stopping the timer/microphone if you navigate away from the page and don't manually stop it.
If that's not it, are you ensuring that all your microphone operations are being executed on the same thread? (Just a thought.)

How do I tell my C# application to close a file it has open in a FileInfo object or possibly Bitmap object?

So I was writing a quick application to sort my wallpapers neatly into folders according to aspect ratio. Everything is going smoothly until I try to actually move the files (using FileInfo.MoveTo()). The application throws an exception:
System.IO.IOException
The process cannot access the file because it is being used by another process.
The only problem is, there is no other process running on my computer that has that particular file open. I thought perhaps that because of the way I was using the file, perhaps some internal system subroutine on a different thread or something has the file open when I try to move it. Sure enough, a few lines above that, I set a property that calls an event that opens the file for reading. I'm assuming at least some of that happens asynchronously. Is there anyway to make it run synchronously? I must change that property or rewrite much of the code.
Here are some relevant bits of code, please forgive the crappy Visual C# default names for things, this isn't really a release quality piece of software yet:
private void button1_Click(object sender, EventArgs e)
{
for (uint i = 0; i < filebox.Items.Count; i++)
{
if (!filebox.GetItemChecked((int)i)) continue;
//This calls the selectedIndexChanged event to change the 'selectedImg' variable
filebox.SelectedIndex = (int)i;
if (selectedImg == null) continue;
Size imgAspect = getImgAspect(selectedImg);
//This is gonna be hella hardcoded for now
//In the future this should be changed to be generic
//and use some kind of setting schema to determine
//the sort/filter results
FileInfo file = ((FileInfo)filebox.SelectedItem);
if (imgAspect.Width == 8 && imgAspect.Height == 5)
{
finalOut = outPath + "\\8x5\\" + file.Name;
}
else if (imgAspect.Width == 5 && imgAspect.Height == 4)
{
finalOut = outPath + "\\5x4\\" + file.Name;
}
else
{
finalOut = outPath + "\\Other\\" + file.Name;
}
//Me trying to tell C# to close the file
selectedImg.Dispose();
previewer.Image = null;
//This is where the exception is thrown
file.MoveTo(finalOut);
}
}
//The suspected event handler
private void filebox_SelectedIndexChanged(object sender, EventArgs e)
{
FileInfo selected;
if (filebox.SelectedIndex >= filebox.Items.Count || filebox.SelectedIndex < 0) return;
selected = (FileInfo)filebox.Items[filebox.SelectedIndex];
try
{
//The suspected line of code
selectedImg = new Bitmap((Stream)selected.OpenRead());
}
catch (Exception) { selectedImg = null; }
if (selectedImg != null)
previewer.Image = ResizeImage(selectedImg, previewer.Size);
else
previewer.Image = null;
}
I have a long-fix in mind (that's probably more efficient anyway) but it presents more problems still :/
Any help would be greatly appreciated.
Since you are using your selectedImg as a Class scoped variable it is keeping a lock on the File while the Bitmap is open. I would use an using statement and then Clone the Bitmap into the variable you are using this will release the lock that Bitmap is keeping on the file.
Something like this.
using ( Bitmap img = new Bitmap((Stream)selected.OpenRead()))
{
selectedImg = (Bitmap)img.Clone();
}
New answer:
I looked at the line where you do an OpenRead(). Clearly, this locks your file. It would be better to provide the file path instead of an stream, because you can't dispose your stream since bitmap would become erroneous.
Another thing I'm looking in your code which could be a bad practice is binding to FileInfo. Better create a data-transfer object/value object and bind to a collection of this type - some object which has the properties you need to show in your control -. That would help in order to avoid file locks.
In the other hand, you can do some trick: why don't you show streched to screen resolution images compressing them so image size would be extremly lower than actual ones and you provide a button called "Show in HQ"? That should solve the problem of preloading HD images. When the user clicks "Show in HQ" button, loads that image in memory, and when this is closed, it gets disposed.
It's ok for you?
If I'm not wrong, FileInfo doesn't block any file. You're not opening it but reading its metadata.
In the other hand, if you application shows images, you should move to memory visible ones and load them to your form from a memory stream.
That's reasonable because you can open a file stream, read its bytes and move them to a memory stream, leaving the lock against that file.
NOTE: This solution is fine for not so large images... Let me know if you're working with HD images.
using(selectedImg = new Bitmap((Stream)selected))
Will that do it?

Resources