-
Notifications
You must be signed in to change notification settings - Fork 424
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
[Proposal] Add MediaElement as TextureView in Android #2526
Comments
@jonmdev It sounds like you already have the skills to modify the code so how about I help you with the bits that you aren't sure on - how to contribute to open source? |
Okay, I'm certainly game to give it a shot. I cloned the repository and I am looking into it. The constructor is still roughly the same in
The constructor This is the one we need (same as in my workaround above). We must pass in the IAttributeSet that will make it a TextureView here. I researched this extensively when I first studied this 9-11 months ago and I could find no way to dynamically generate the IAttrituteeSet except from an XML file. Every other method I tried failed with errors. So as noted above, I had to add a textureview.xml to
Then I could pass this in by:
The world has changed in even 9-11 months and now asking ChatGPT, it says things like:
So according to it, this is still the only correct way to do it. Unless @ne0rrmatrix you do know a different or better way? ChatGPT says I can add the xml anywhere arbitrarily in the MediaElement folder path and then add to the MediaElement csproj like:
So I am trying that unless advised otherwise. Seems to be working so far. |
@jonmdev thank you! I'll defer to James for the assistance with the media specific bits surrounding xml files, etc. for now I'd like to focus on helping with the general approach to contributing. Sadly you can't just clone this repository because you don't have permission to push branches. Therefore to save pain later I would like to guide you through the steps you need to follow. They are:
This also looks pretty helpful https://www.freecodecamp.org/news/how-to-fork-a-github-repository/ |
Oh geez. Okay I'll do all that. I'm already figuring out the xml stuff. I think it's working so far. This shouldn't take more than a day I don't think. I'll copy over to a fork and post back if any issues or when done. |
Great work! Feel free to reach out if you need anything! Are you on the discord server for the toolkit? |
Sorry about the late reply. Yes you correct. Your method is the only way this will work atm. I had a few ideas but they did not work out. So yes you are 100 correct about this. |
Well I'm dead ended.
(For some reason I had to manually add the handler or it said it didn't exist.) I can now build this sample project with a
"Java.Lang.AbstractMethodError: 'abstract method "void androidx.media3.common.Player$Listener.onSurfaceSizeChanged(int, int)"'" And it breaks. This is without me even implementing my new code. So already I have two weird behaviors (1) Had to manually add the handlers and (2) Getting exception on existing method. What did I do wrong? This is the sort of thing I have no idea about and I am just wasting time with. I can write the TextureView code. I have done it before. Would likely take me a few hours to do all of it. But I have no idea about any of this. Can't add the new method if the existing won't work. Any help or solution? https://github.com/jonmdev/CommunityToolkit-Maui/tree/AddAndroidTextureView |
Your texture view is referencing media 2 and needs to use AndroidX.Media3.UI.PlayerView in textureview.xml |
I put together a quick and dirty sample for you to look at and maybe use if it does what you need? main...ne0rrmatrix:MauiOld:TextureViewIdea |
Thanks and you are correct I missed that but that is not the issue. I have removed the xml completely (deleted it or removed the include on csproj) and it still won't build to Android without: "Java.Lang.AbstractMethodError: 'abstract method "void androidx.media3.common.Player$Listener.onSurfaceSizeChanged(int, int)"'" This is just doing the steps I said and no code changes at all. I am just trying to get a working demo project that references CommunityToolkit so I can modify Community Toolkit and see the changes in the demo project. But I don't know how to make that work. Irrespective of any code changes. As noted, I am getting Handler doesn't exist errors if I don't add the manual handler association in mauibuild.cs and I am getting Java errors on the current construction of the PlayerView. So clearly something is wrong. This is again with no code changes. Any idea? Did I do the right steps to make this work? Was I supposed to do something else? I actually need to fix Plugin.Maui.Audio next so it is useful for me to know how this is supposed to work. |
@jonmdev I will be posting a sample you can work from in about 5 min. Here is quick image of what I have done so far. |
Here is latest changes. It is working but there is no API. You will need to add that if you want to create a PR for it. I hope this is what you were looking for. https://github.com/ne0rrmatrix/MauiOld/tree/TextureViewIdea If it does not do what you need please reply back. |
The linked GitHub project has working sample. Build it. Goto view. Media
element. Then load texture view page.
…On Mon, Feb 17, 2025, 10:47 jonmdev ***@***.***> wrote:
I put together a quick and dirty sample for you to look at and maybe use
if it does what you need? main...ne0rrmatrix:MauiOld:TextureViewIdea
<main...ne0rrmatrix:MauiOld:TextureViewIdea>
Thanks and you are correct I missed that but that is not the issue. I have
removed the xml completely (deleted it or removed the include on csproj)
and it still wont' build to Android without:
"*Java.Lang.AbstractMethodError:* 'abstract method "void
androidx.media3.common.Player$Listener.onSurfaceSizeChanged(int, int)"'"
This is just doing the steps I said and no code changes at all. I am just
trying to get a working demo project that references CommunityToolkit so I
can modify Community Toolkit and see the changes in the demo project. But I
don't know how to make that work. Irrespective of any code changes.
As noted, I am getting Handler doesn't exist errors if I don't add the
manual handler association in mauibuild.cs and I am getting Java errors on
the current construction of the PlayerView. So clearly something is wrong.
This is again with no code changes.
Any idea? Did I do the right steps to make this work? Was I supposed to do
something else.
—
Reply to this email directly, view it on GitHub
<#2526 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AA7ZRN6XLDDDOCARH7APNV32QIVFNAVCNFSM6AAAAABXIU6MSSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDMNRTHA4DAMBWGA>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
[image: jonmdev]*jonmdev* left a comment (CommunityToolkit/Maui#2526)
<#2526 (comment)>
I put together a quick and dirty sample for you to look at and maybe use
if it does what you need? main...ne0rrmatrix:MauiOld:TextureViewIdea
<main...ne0rrmatrix:MauiOld:TextureViewIdea>
Thanks and you are correct I missed that but that is not the issue. I have
removed the xml completely (deleted it or removed the include on csproj)
and it still wont' build to Android without:
"*Java.Lang.AbstractMethodError:* 'abstract method "void
androidx.media3.common.Player$Listener.onSurfaceSizeChanged(int, int)"'"
This is just doing the steps I said and no code changes at all. I am just
trying to get a working demo project that references CommunityToolkit so I
can modify Community Toolkit and see the changes in the demo project. But I
don't know how to make that work. Irrespective of any code changes.
As noted, I am getting Handler doesn't exist errors if I don't add the
manual handler association in mauibuild.cs and I am getting Java errors on
the current construction of the PlayerView. So clearly something is wrong.
This is again with no code changes.
Any idea? Did I do the right steps to make this work? Was I supposed to do
something else.
—
Reply to this email directly, view it on GitHub
<#2526 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AA7ZRN6XLDDDOCARH7APNV32QIVFNAVCNFSM6AAAAABXIU6MSSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDMNRTHA4DAMBWGA>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
Here is a copy of your project updated to dotnet 9 and is now not crashing. https://github.com/ne0rrmatrix/MediaElementOverlapBug/tree/master |
Thanks @ne0rrmatrix but as I said, I need to also do this with Plugin.Maui.Audio (as that is missing audio compression options which I already solved similarly ~8 months ago but similarly by just copying and pasting the code out rather than pushing an update). The project owners for that similarly asked me to update the project but I didn't know how (same problem as now). So I really need to know what to do start to finish to do this. (Not the code fix itself, but the process of working this way.) I have deleted everything, started again now from the beginning, and enumerated all my steps in detail. I hope you or @bijington can tell me perhaps what I am doing wrong. (i) FORK & BRANCH COMMUNITY TOOLKIT
(ii) ADD A BASIC TEST PROJECT TO PLAY WITH
(iii) ADD MEDIA ELEMENT TO TEST PROJECT
So again this is with no changes to any underlying code. I am just trying to set up a basic sandbox (default Maui test project) with a reference to my branched/forked CommunityToolkit so I can demo the MediaElement changes once I make them and it gives me this error. Did something change in the implementation of MediaElement? Were my steps wrong above? I have pushed an update so it is now in the exact state as above and I documented every step as I took it so nothing was missed. https://github.com/jonmdev/Maui-CommunityToolkit/tree/AddAndroidTextureView Was I supposed to do something else instead? Thanks for any suggestion. |
I am happy to help you if you want to create a PR and add the feature you have requested. I provided a fixed sample of you app that has been updated for dotnet 9.x. If you need help with Plugin.Maui.Audio I suggest going to that repo and starting a discussion with the author about it. |
I am just trying to understand how to do this process. It is not specific for one package or another since I presume this requires the same workflow either way. (Point of reference @bijington was the one who suggested the compression options should be committed if someone is willing, so again same story again in both threads with my inability here.) I listed all the steps I took to set up the forked repo and a demo project and yet I am getting an error from that with no changes to the underlying CommunityToolkit. Do you know if I followed all the steps correctly as listed or why my workflow is not working? If I did something wrong, what are the correct steps to fork the project and add a sample to it with a reference that works? If you are not keen on discussing that it's fine of course (you owe me nothing obviously), but I cannot do anything meaningful in any greater sense with any of this unless I understand how to at least set up a basic configuration. @bijington can you perhaps explain? |
You did nothing wrong. I was confused by what you were asking. You referenced this project, a different project, and I was unable to see what you needed help with or how to proceed. |
Thank you! That is very helpful to know I at least set it up correctly. So it appears then perhaps I have unveiled a new bug. I tested and the bug is confirmed from everything I can see. I posted a bug report on it accordingly: #2529 I will wait for any ideas or suggestions on fixing that before proceeding with this as I cannot work in C# with MediaElement unless I use Thanks again for looking at things and at least letting me know my method of setting up the project was correct. |
@jonmdev i am more than happy to assist where I can. It sounds like your approach is a good one and the steps look right. You may have been able to avoid creating a sample project and instead use the sample that comes with the toolkit codebase - it is a lot more complex than a simple application though so just use whatever works best for you. As for other steps I'd be more than happy to walk you through bits on a call or via email or on here, again whatever works best for you. I really appreciate you putting in the effort to making the toolkit better. I'd also be happy to help out with the audio plugin |
SOLUTIONHere is my solution. I will explain in words what I did so it is easy to review if that helps. A lot of the changes you will see there are due to the default Maui project I added for testing as I also manually added the fix here to Here are the steps of the solution. Add to csproj to Include
|
Thanks for the detailed breakdown, usually I would say it's easier to view in a PR but this is really helpful! The one issue I can spot on first glance is the approach of adding a parameter to the constructor for MediaElement, this would not be usable in XAML. I think we could follow the options pattern like is already done for converters, etc. I do like the approach for options though so I like the idea. In fact I had a PR open that tried to add in options for MediaElement - I see this as just setting the defaults and developers can still override on a per instance basis |
Glad to hear it. I have thought about the same things you mention as well. As I said in my post, this can still be used in xaml by deriving the class:
This I am not aware of any other good option for this other than to set the options as a parameter. I believe we have no other opportunity to certainly access the underlying ExoPlayer PlayerView Android constructor otherwise before it is too late. Once we do The only other way I can think of it could be done would be to let it build as it is (no constructor parameter), then run a function to change the view type after building. But this is then highly inefficient and dangerous, as we will have to build a SurfaceView by default and then discard it from the Android hierarchy to create a new TextureView to replace it afterwards and it is just asking for trouble in my opinion to do it that way. It is way, way, way more complicated for a considerably slower and less efficient method. We will have to reset all the parameters over to the new TextureView as we hotswap it out from the default SurfaceView and this is just slowing everything down and dangerous if something goes wrong. If the SurfaceView starts playing and then we need to transfer the playing state this could create major glitches and weird undefined behavior. There is no practical reason people would want to switch the View type after building either - you would want one or the other for a given use case, so I believe this would be highly overengineering a simple problem with too much danger and no obvious reward. There may not be a perfect solution but I think the current proposal is great in my opinion (fits everything I need certainly but perhaps I am biased 🙂) and certainly it is at least better than the current circumstance where we have no TextureView at all. This method would provide the best performance and safest most efficient construction, because we are guaranteed to only construct the Android view once, which is also important in the real world. The method proposed is safe and guaranteed to work every time without new bugs. You know more about these things than I do so if you know of another way of safely getting the Otherwise I think this is the best approach from all the time I have thought about it and everything I know, which is why I went this route. I think the safety and speed of the method are very important, especially on mobile devices and this is maximally safe and efficient. Thanks again and for any further thoughts. |
I have a thought on a pattern we can use to achieve this without having to supply it as a parameter in the constructor but first I would like to take a step back and ask whether there is ever a time a developer would not want to use |
SurfaceView is the default for exoplayer. Switching to texture view is an option that available. It is not advised to use it unless you have a specific need for it. https://developer.android.com/media/media3/ui/playerview#surfacetype |
The surface_type attribute of PlayerView lets you set the type of surface used for video playback. Besides the values spherical_gl_surface_view (which is a special value for spherical video playback) and video_decoder_gl_surface_view (which is for video rendering using extension renderers), the allowed values are surface_view, texture_view and none. If the view is for audio playback only, none should be used to avoid having to create a surface because doing so can be expensive. If the view is for regular video playback then surface_view or texture_view should be used. SurfaceView has a number of benefits over TextureView for video playback: Significantly lower power consumption on many devices. Qouted from google site: https://developer.android.com/media/media3/ui/playerview#surfacetype |
Yeah as @ne0rrmatrix said SurfaceView is the default. This is because it is more efficient. It is more of a direct rendering to the screen, which is why it doesn't obey normal layout rules and overlays. I have read people describe it as being a "punched hole" through the screen in the rendering system. So if you just want to make an efficient full screen video player (like for watching 2 hour Hollywood movies), you will typically want SurfaceView. If you want something that integrates into a modern Maui layout, with overlapping elements or rounded corners, etc., you will want TextureView. I am open to any ideas for how it could work as long as we have both options and the method does not necessitate any unsafe or unnecessary inefficiencies like building then destroying the entire default view before remaking the correct desired view. As noted, 99.99999% of the time you will need one or the other. There is no practical reason to switch once it is made, and if you are going to switch in some rare edge case, I think you are better off in my opinion discarding the entire MediaElement since the Exoplayer (whether surfaceview or textureview) essentially IS the MediaElement for Android than trying to rewrite the entire guts to handle live swapping out the core without causing catastrophe. Thanks. Almost done adding AAC audio compression to Plugin.Maui.Audio also. I'll post that likely tomorrow. |
Thank you both for the detailed responses. I think rather than requiring developers to need to subclass MediaElement we could achieve it as follows: Add optionsEnable the It could be used like: builder.UseCommunityToolkitMediaElement(options =>
{
#if ANDROID
options.ViewType = AndroidViewType.TextureView;
#endif
}); Internally this could set something like Then we just use this when a new MediaElement is created. Failing that I wonder if there is an approach we could use through the handler architecture although as you suggested it is likely too late for this. |
Here is an example of how to use options in Media Element based on how we do it for other things. https://github.com/ne0rrmatrix/MauiOld/tree/MediaElementOptions This example was made as a possible solution to something else but should demonstrate how it can be done. |
Here is a complete example of texture view being implemented if you are looking for an example. https://github.com/ne0rrmatrix/MauiOld/tree/TextureViewIdea It includes adding a sample page for texture view. It is supported out of the box for windows and ios. It just works. It uses an options class and it works like other option classes we currently uses. It also integrates with current methods and classes. It is based upon @jonmdev code. |
Personally, this would be less ideal in my opinion as it would then force users to always use only one type of Android View for all Android MediaElement's throughout your project. Whereas while it may not be considered beautiful to derive from MediaElement to customize it, we still preserve both methods safely for all users and they can use both throughout their project with zero bugs or errors as well in doing so. I also think 4 lines of deriving a C# class off in a small file somewhere is significantly less intrusive than adding potentially many lines of "options" into the builder chain of MauiProgram.cs but this is perhaps subjective. My MauiProgram.cs is already a mess of compiler flags and other configuration information. 😂 My perspective in general on this subject is that "perfect" does not need to be the enemy of "good". Currently for the entire lifetime of this MediaElement project there has been no TextureView support at all. This method safely and efficiently adds it with full backwards compatibility. No one's current projects will be broken in any way by the addition. It just adds an extra option which is easy and safe to use. It allows full flexibility. And it is absolutely safe and fast. To me that's a good step forward and progress is good. Btw, I just finished Plugin.Maui.Audio AAC audio compression and posted it here. But we can talk about that over there. 🙂 |
It just occurs to me @bijington , perhaps we could even do both methods? Why not? 1) GLOBAL SETTINGWe could have your method as one option to set default options globally for the project: builder.UseCommunityToolkitMediaElement(options => {
options.ViewType = AndroidViewType.TextureView;
}); (No compiler flags are needed as setting this doesn't hurt non-Android builds and this code is cross platform safe.) This would set the global default "options" used on construction of all MediaElements after that in the project 2) INDIVIDUAL OVERRIDEThen in addition, we can also let people use my method:
or for xaml:
LOGICThe logic would be that on MediaElement construction the constructor is changed to: public MediaElement(MediaElementOptions? mediaElementOptions = null)
{
// SOLVE DEFAULT IF NO ARGUMENT SET (OTHERWISE USE ARGUMENT AS OVERRIDE)
if (mediaElementOptions == null) {
// (1) CHECK FOR STATIC OR GLOBAL "OPTIONS" SET IN ON BUILDER
// (2) IF NOTHING IS FOUND CREATE NEW DEFAULT
mediaElementOptions = new();
}
// USE SOLVED RESULT
this.MediaElementOptions = mediaElementOptions;
} Thus the order of operations for solving the settings is:
RESULTThus with this combined approach you can allow many possibilities:
Not bad I think? And still maximally safe and fast. I will add that now and we can see. |
UPDATEThat was incredibly simple to add. Both methods for setting the Add
|
I think the approach sounds good. Do you think you could open a PR so that it will be easier to review and potentially merge? |
Cool! Done I think. |
Feature name
MediaElement as TextureView in Android
Link to discussion
#1891
Progress tracker
Summary
It is now 11 months since I raised the issue of MediaElement not supporting TextureView here for Android:
#1773
And 9 months since everyone seemed to agree this should be added:
#1891
The implementation of adding this is very simple (or at least it was back when I last looked at it).
My workaround 9 months ago was to add an xml to Platforms/Android/Resources/layout.textureview.xml:
Then in MediaManager.Android.cs we could do:
In other words we just need to be able to manually pass in some attribute xml into the StyledPlayerView constructor.
I worked around this issue by copying and pasting the entire MediaElement out of Community Toolkit. The code above is all I had to change to make it a TextureView, as again this is intended by Google to be a very simple thing. This has served fine as a temporary solution. But it is a timebomb for me as now everything from that old version is becoming obsoleted.
The addition of TextureView support is necessary for virtually any normal layout functions in Android as noted in the prior two discussions.
Is there any way to add this to the new version of Community Toolkit?
@ne0rrmatrix I believe claimed he knew a way to make the TextureView without needing any xml, but I could not figure out any other way to do it. I am not sure if these constructors have changed also since then. I figure it is worth reassessing and seeing what the solution is if we can still fix this somehow.
Thanks for any support on this.
Motivation
Android Exoplayer can be rendered as a SurfaceView (which does not respect layout like overlapping objects or masking) or a TextureView (which does respect layout like overlapping objects and masking).
Normal modern layouts (eg. with rounded corners or overlapping elements) will need TextureView to integrate video into those views.
Detailed Design
As above, Exoplayer typically just needs the TextureView passed as an argument on construction. So we need a way to construct MediaElement with an argument that accounts for this.
Usage Syntax
My belief as previously expressed is we should have something like:
As this can be used for other construction parameters later if ever needed and it is platform agnostic (could hold various platform specific configuration elements/enums.
Then in usage we can do:
Pretty simple, logical, and straightforward I think.
Drawbacks
There is no downside. The lack of TextureView is a glaring hole in this project which is demonstrated in the examples I have given. Lacking TextureView prevents the MediaElement from being used in any modern looking interface. It forces us to do crazy workarounds like I described of copying and pasting the entire MediaElement into our code just to change 3-5 lines or we can't make our modern looking layouts work in Android.
Unresolved Questions
I am not knowledgeable or capable of how to modify these open source types of projects on GitHub myself and pushing updates or passing tests, etc. I have never done this before and have no training in doing so. So while I very much hope this will be fixed as I expect my temporary solution to self destruct imminently (forcing me to redo all that manual importing of code again which is a messy and seemingly pointless temporary job), I cannot do much more to fix it myself. Thus I really hope someone who does know how to fix these types of projects could add a simple method like I described or something like it so we can all benefit from a stable and long term fix.
Thanks for any help and all the hard work on the project.
The text was updated successfully, but these errors were encountered: