성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] 한 번도 궁금한 적이 없었는데, If I mark my t...
[정성태] 그냥 RSS Reader 기능과 약간의 UI 편의성 때문에 사용...
[이종효] 오래된 소프트웨어는 보안 위협이 되기도 합니다. 혹시 어떤 기능...
[정성태] @Keystroke IEEE의 문서를 소개해 주시다니... +_...
[손민수 (Keystroke)] 괜히 듀얼채널 구성할 때 한번에 같은 제품 사라고 하는 것이 아...
[정성태] 전각(Full-width)/반각(Half-width) 기능을 토...
[정성태] Vector에 대한 내용은 없습니다. Vector가 닷넷 BCL...
[orion] 글 읽고 찾아보니 디자인 타임에는 InitializeCompon...
[orion] 연휴 전에 재현 프로젝트 올리자 생각해 놓고 여의치 않아서 못 ...
[정성태] 아래의 글에 정리했으니 참고하세요. C# - Typed D...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>C# MAUI - MediaElement Source 경로 지정 방법</h1> <p> 지난 MAUI 예제에서는,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > C# - MAUI에서 MediaElement 사용 ; <a target='tab' href='https://www.sysnet.pe.kr/2/0/13624'>https://www.sysnet.pe.kr/2/0/13624</a> </pre> <br /> https로 외부 mp4 파일을 지정해 재생을 했는데요, 만약 mp4 파일을 포함하는 경우라면 어떻게 해야 할까요? 예를 들어, 아래의 사이트에 있는 mp4 파일을 다운로드해,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Sample MP4 files download ; <a target='tab' href='https://file-examples.com/index.php/sample-video-files/sample-mp4-files/'>https://file-examples.com/index.php/sample-video-files/sample-mp4-files/</a> </pre> <br /> 닷넷 csproj의 전통적인 방식대로 CopyToOutputDirectory 설정을 통해 빌드 시 mp4 파일을 패키지 자체에 담아서 배포할 수 있을 것입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <Project Sdk="Microsoft.NET.Sdk"> <!-- ...[생략]... --> <span style='color: blue; font-weight: bold'><ItemGroup> <None Include="..\file_example_MP4_1920_18MG.mp4" Link="file_example_MP4_1920_18MG.mp4"> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> </None> </ItemGroup></span> </Project> </pre> <br /> 직관적으로, 이 파일을 재생하려면 단순히 이렇게 파일명만 Source에 설정하고 싶겠지만,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <toolkit:MediaElement Grid.Row="0" x:Name="mediaPlayer" ShouldAutoPlay="True" <span style='color: blue; font-weight: bold'>Source="file_example_MP4_1920_18MG.mp4"</span> /> </pre> <br /> 이런 상태로 실행해 보면 예외가 발생합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > #if DEBUG && !DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION UnhandledException += (sender, e) => { if (global::System.Diagnostics.Debugger.IsAttached) global::System.Diagnostics.Debugger.Break(); }; #endif // 예외: The parameter is incorrect. The specified path (file_example_MP4_1920_18MG.mp4) is not an absolute path, and relative paths are not permitted. </pre> <br /> 대충, <a target='tab' href='https://learn.microsoft.com/en-us/uwp/api/windows.ui.xaml.controls.image.source#setting-source-in-xaml'>Store App 당시의 경험으로 ms-appx 프로토콜을 사용</a>하면 Windows에서 동작은 합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <toolkit:MediaElement Grid.Row="0" x:Name="mediaPlayer" ShouldAutoPlay="True" <span style='color: blue; font-weight: bold'>Source="ms-appx:///file_example_MP4_1920_18MG.mp4"</span> /> </pre> <br /> 반면 Android에서는 ms-appx 프로토콜을 이해할 수 없어 MalformedURLException이 발생합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > ...[생략]... Caused by: com.google.android.exoplayer2.upstream.HttpDataSource$HttpDataSourceException: java.net.MalformedURLException: unknown protocol: ms-appx </pre> <br /> <hr style='width: 50%' /><br /> <br /> 이에 대해서는 공식 문서에 자세하게 나와 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > MediaElement - Play local media ; <a target='tab' href='https://learn.microsoft.com/en-us/dotnet/communitytoolkit/maui/views/mediaelement?tabs=windows#play-local-media'>https://learn.microsoft.com/en-us/dotnet/communitytoolkit/maui/views/mediaelement?tabs=windows#play-local-media</a> </pre> <br /> 그러니까, 이런 경우 file_example_MP4_1920_18MG.mp4 파일을 MAUI 프로젝트의 /Resources/Raw 디렉터리에 포함시키면 빌드 시 Android apk 배포 패키지의 /assets 디렉터리에 자동으로 배치가 됩니다.<br /> <br /> 그다음, 응용 프로그램에 포함한 유형이니까 "embed://" 프로토콜로 다음과 같이 Source에 지정하면,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <toolkit:MediaElement Grid.Row="0" x:Name="mediaPlayer" Source="<span style='color: blue; font-weight: bold'>embed://</span>file_example_MP4_1920_18MG.mp4" /> </pre> <br /> 실행 시 정상적으로 로딩이 됩니다. 위의 동작을 코드로도 할 수 있는데, embed 유형이니까 MediaSource.FromResource를 호출하면 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // embed에는 MediaSource.FromResource 사용 ResourceMediaSource? src = <span style='color: blue; font-weight: bold'>MediaSource.FromResource</span>("file_example_MP4_1920_18MG.mp4"); mediaPlayer.Source = src; mediaPlayer.Play(); </pre> <br /> 예상할 수 있겠지만, XAML에서 Source 속성에 문자열을 설정하면 Type Converter가 관여해 자동으로 ResourceMediaSource로 바꿔준다고 합니다.<br /> <br /> embed 외에 기기의 파일 시스템 경로를 지원하는 filesystem 프로토콜도 있는데요, 가령 윈도우를 대상으로 한 MAUI에서는 다음과 같은 식으로 지정할 수 있습니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <toolkit:MediaElement Grid.Row="0" x:Name="mediaPlayer" ShouldAutoPlay="True" <span style='color: blue; font-weight: bold'>Source="filesystem://c:\temp\file_example_MP4_1920_18MG.mp4"</span> /> </pre> <br /> 코드로는 이렇게 지정합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // filesystem에는 MediaSource.FromFile 사용 FileMediaSource? src = <span style='color: blue; font-weight: bold'>MediaSource.FromFile</span>(@"C:\temp\file_example_MP4_1920_18MG.mp4") as FileMediaSource; mediaPlayer.Source = src; mediaPlayer.Play(); </pre> <a name='source_by_code'></a> <br /> 하지만 MAUI의 특성상 대부분 Android와 같은 폰 환경을 목표로 개발할 테니, XAML에 "filesystem" 프로토콜을 직접 지정하는 것은 현실성이 없고 플랫폼 환경에 따른 코드를 사용하는 식으로 접근하게 될 것입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > FileMediaSource? src = null; #if ANDROID // docPath == <a target='tab' href='https://www.sysnet.pe.kr/2/0/13629'>"/data/user/0/com.companyname.simpleplayer/files/Documents"</a> string docPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); string filePath = Path.Combine(docPath, "file_example_MP4_1920_18MG.mp4"); src = MediaSource.FromFile(filePath) as FileMediaSource; #elif WINDOWS src = MediaSource.FromFile(@"C:\temp\file_example_MP4_1920_18MG.mp4") as FileMediaSource; #endif </pre> <br /> (<a target='tab' href='https://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=2179&boardid=331301885'>첨부 파일은 이 글의 예제 코드를 포함</a>합니다. - 파일 크기 축소를 위해 폰트 및 mp4 예제 파일은 제거했습니다.)<br /> <br /> <hr style='width: 50%' /><br /> <a name='launch_mode'></a> <br /> 테스트하면서 약간 의문이 남는 점이 있어 기록으로 남깁니다. ^^ 우선, <a target='tab' href='https://learn.microsoft.com/en-us/dotnet/communitytoolkit/maui/views/mediaelement?tabs=android#platform-specific-initialization'>문서에 보면 안드로이드의 경우</a> LaunchMode, ResizeableActivity 속성을 설정해야 한다고 나옵니다. <br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > // .\Platforms\Android\MainActivity.cs using Android.App; using Android.Content.PM; namespace SimplePlayer; [Activity(Theme = "@style/Maui.SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density, <span style='color: blue; font-weight: bold'>LaunchMode = LaunchMode.SingleTask, ResizeableActivity = true</span> )] public class MainActivity : MauiAppCompatActivity { } </pre> <br /> 하지만, 딱히 저 옵션에 따라 변화는 없었습니다. (혹시 이력을 알고 계신 분은 덧글 부탁드립니다. ^^)<br /> <br /> 다른 하나는, 테스트를 하다 보면 Source가 지정된 상황에서 ShouldAutoPlay=True여도 자동 재생이 안 되는 경우가 있습니다. 아마도 버그일 테니 나중에 고쳐질 듯하지만 그때까지는 뭔가 우회로를 찾아야 합니다.<br /> <br /> 그나마 적당해 보이는 MediaOpened 이벤트를 이용하려고 했는데,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <toolkit:MediaElement Grid.Row="0" x:Name="mediaPlayer" ShouldAutoPlay="True" Source="embed://file_example_MP4_1920_18MG.mp4" <span style='color: blue; font-weight: bold'>MediaOpened="OnMediaOpened"</span> /> </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > private void OnMediaOpened(object sender, EventArgs e) { mediaPlayer.Play(); // 예외 발생: System.Runtime.InteropServices.COMException } </pre> <br /> 아쉽게도 Media 파일만 준비되었을 뿐 아직 내부 컨트롤은 준비가 안 된 듯, 이 시점에는 예외가 발생합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > System.Runtime.InteropServices.COMException HResult=0x8001010E Message= Source=WinRT.Runtime StackTrace: at WinRT.ExceptionHelpers.<ThrowExceptionForHR>g__Throw|39_0(Int32 hr) at ABI.Microsoft.UI.Xaml.Controls.IMediaPlayerElementMethods.get_MediaPlayer(IObjectReference _obj) at Microsoft.UI.Xaml.Controls.MediaPlayerElement.get_MediaPlayer() at CommunityToolkit.Maui.Core.Views.MediaManager.PlatformPlay() at CommunityToolkit.Maui.Core.Views.MediaManager.Play() at CommunityToolkit.Maui.Core.Handlers.MediaElementHandler.MapPlayRequested(MediaElementHandler handler, MediaElement mediaElement, Object args) at Microsoft.Maui.CommandMapper`2.<>c__DisplayClass6_0.<Add>b__0(IElementHandler h, IElement v, Object o) at Microsoft.Maui.CommandMapper.InvokeCore(String key, IElementHandler viewHandler, IElement virtualView, Object args) at Microsoft.Maui.CommandMapper.Invoke(IElementHandler viewHandler, IElement virtualView, String property, Object args) at Microsoft.Maui.Handlers.ElementHandler.Invoke(String command, Object args) at CommunityToolkit.Maui.Views.MediaElement.Play() at MauiApp1.MainPage.OnMediaOpened(Object sender, EventArgs e) in C:\temp\MauiApp1\MauiApp1\MainPage.xaml.cs:line 25 at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor) at System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr) </pre> <br /> 그다음 후보로 Loaded 이벤트를 선택했는데,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <toolkit:MediaElement Grid.Row="0" x:Name="mediaPlayer" ShouldAutoPlay="True" Source="embed://file_example_MP4_1920_18MG.mp4" <span style='color: blue; font-weight: bold'>Loaded="OnMediaLoaded"</span> /> </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > private void OnMediaLoaded(object sender, EventArgs e) { if (mediaPlayer.CurrentState != CommunityToolkit.Maui.Core.Primitives.MediaElementState.Playing) { mediaPlayer.Play(); } } </pre> <br /> 일단은 잘됩니다. ^^<br /> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
6400
(왼쪽의 숫자를 입력해야 합니다.)