Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Media: Internally keep a reference to the last set Media #205

Closed
wants to merge 8 commits into from

Conversation

mfkl
Copy link
Member

@mfkl mfkl commented Apr 26, 2021

Description of Change

libvlc_media_player_get_media increments the ref count of the media, which may easily
cause a memory leak, as this is very unusual behavior for C# property getter to
have these types of consequences. Users don't have the reflex to dispose every Media returned
by the getter property.

Holding a ref internally in the mediaplayer prevents from incrementing the native ref count
of the media object.

Issues Resolved

API Changes

None, but the usage is subtly changed. Docs should probably mentioned it somewhere.

Platforms Affected

  • Core (all platforms)

Behavioral/Visual Changes

None

Before/After Screenshots

Not applicable

Testing Procedure

I have not tested this thoroughly.

PR Checklist

  • Rebased on top of the target branch at time of PR
  • Changes adhere to coding standard

@jeremyVignelles
Copy link
Collaborator

This is a breaking change for those who already did that properly. If they Disposed the media by themselves, the media ends up getting disposed multiple times.

Aren't there some cases where the libvlc media player decides to change the media internally? like making it null on Stop or when playing a playlist?

@mfkl
Copy link
Member Author

mfkl commented Apr 26, 2021

This is a breaking change for those who already did that properly. If they Disposed the media by themselves, the media ends up getting disposed multiple times.

I know... :-( But trying to find ways to fix it anyway, for 3.x. If it's not possible, the fix will be 4.x only.

Aren't there some cases where the libvlc media player decides to change the media internally? like making it null on Stop or when playing a playlist?

Tried to find these cases but failed. We don't expose the medialistplayer object so that helps somewhat to reduce potentially affected use cases.

}
set
{
if(_media?.NativeReference != IntPtr.Zero)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either media is null or it's not, but if it's not null, I don't think its native reference can be Zero. Either way, it's up to _media.Dispose() to check that (same in MediaPlayer.Dispose)

@mfkl mfkl mentioned this pull request Apr 28, 2021
@jeremyVignelles
Copy link
Collaborator

Thinking out loud:
Should we remove IDisposable from Media and handle disposal differently than in C#? I see several advantages:

  • Avoids risk of multiple disposal, and makes it clear there is a breaking change
  • Users don't have to wonder if they need to Dispose() it or not
  • MediaPlayer becomes in charge of managing the memory properly to avoid memory leaks.

Drawbacks : How to reuse a Media between two Play() ? If it is released as soon as the player starts another media, we would end up parsing the media over and over again...

@mfkl
Copy link
Member Author

mfkl commented May 3, 2021

Yes.. I see what you mean :-) My problem with this design is that it creates a layer of abstraction over LibVLC and I'd like to avoid that because it is bound to grow with time, and become problematic as the underlying LibVLC API changes.

This awkward libvlcsharp API won't be fixed for 3.x, because as you noted it's a subtle breaking change which has a high risk of breaking user-code. However, we can definitly fix it for 4.x and document it as a breaking change.

I don't understand yet why LibVLC must increment the ref count when calling get_media on a media that already has a refcount > 1. Maybe changing LibVLC is an option?

libvlc_media_player_new_from_media also increments the media ref count, as well as libvlc_media_player_set_media...

@jeremyVignelles
Copy link
Collaborator

I don't think so. If you don't count the usages, libvlc won't be able to know that the media is still kept for later use and that it is not expected to be destroyed

@mfkl
Copy link
Member Author

mfkl commented May 4, 2021

So I tried to call media_release repeatedly and it seems that libvlc is fine with it... no crash.

2 solutions that I have so far. Aiming for something simple...

  1. what's currently in this branch. Proxy the media by keeping a single ref in the binding to prevent from incrementing the native ref count.
    Advantage: Can use that property getter (which is really convenient) as much as we want, like a normal C# property.
    Disadvantage: ???
  2. rename the property from mediaplayer.Media to mediaplayer.NewMedia (or make it a method), and document that users need to dispose that.
    Advantage: Doesn't circumvent the native API, uses the native ref count as intended.
    Disadvantage: People won't read the doc and dispose it, so it will cause leak. That's for sure.

Still looking for other solutions. No special hurry as this is v4 anyway. If solution 1 doesn't break usercode, we might actually fix this for v3

@jeremyVignelles
Copy link
Collaborator

  1. Disadvantage : You can't reuse Media for A/B loops
  2. I'd be in favor of making it a method. Renaming the property doesn't really add value.
  3. We could add IDisposable annotations (see my proposal here ) and recommend using an analyzer like IDisposableAnalzyer that would spot such issues, but work is needed here

@mfkl mfkl force-pushed the media-refcount-property-fix branch from 9531e95 to d0fe5df Compare May 11, 2021 07:18
@mfkl
Copy link
Member Author

mfkl commented May 11, 2021

This seems to work quite well so far. Tried to stress the implementation a bit with various tests on the netcore sample. Still not fully convinced this is the way to go though

Only issue I noticed, unrelated to this PR, is that now that the Media is properly getting disposed since last release, the debugger crashes when trying to inspect media object that have been disposed. We maybe should generalize these checks 56b69d9 for the whole interop calls.

mfkl added 4 commits July 26, 2021 14:06
libvlc_media_player_get_media increments the ref count of the media, which may easily
cause a memory leak, as this is very unusual behavior for C# property getter to
have these types of consequences. Users don't have the reflex to dispose every Media returned
by the getter property.

Holding a ref internally in the mediaplayer prevents from incrementing the native ref count
of the media object.

https://code.videolan.org/videolan/LibVLCSharp/-/issues/442
@mfkl mfkl force-pushed the media-refcount-property-fix branch from 56b69d9 to 84250eb Compare July 26, 2021 07:07
@mfkl
Copy link
Member Author

mfkl commented Jul 26, 2021

Added a failing test.

While this approach may seem like a good idea, for now there is a still a few undiscovered gotchas. And the retain/dispose routine is different if you create a mediaplayer from a media or if you set a media on a mediaplayer instance...

@mfkl
Copy link
Member Author

mfkl commented Nov 24, 2021

There needs to be a solution for this problem for libvlcsharp 4.

mfkl referenced this pull request in ispysoftware/iSpy Nov 24, 2021
@mfkl
Copy link
Member Author

mfkl commented Mar 7, 2022

Gotta merge this one soon.

@mfkl
Copy link
Member Author

mfkl commented May 23, 2024

Introduces too much magic. Closing for now.

@mfkl mfkl closed this May 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants