광고 수익은 기아대책 서울본부에 기부합니다.

2013.05.27 18:28 Windows8/Windows Store App
http://msdn.microsoft.com/ko-kr/library/windows/apps/hh986967.aspx

 

저작자 표시 비영리 동일 조건 변경 허락
신고
posted by Town One townone
2013.05.27 15:51 Windows8/C#

http://kaki104.tistory.com/entry/KMusic-Player-Help

저작자 표시 비영리 동일 조건 변경 허락
신고

'Windows8 > C#' 카테고리의 다른 글

KMusic Player  (0) 2013.05.27
Sorting Arrays [C#]  (0) 2013.03.15
posted by Town One townone
2013.05.27 10:56 Windows8/Windows Store App
http://msdn.microsoft.com/ko-kr/library/vstudio/system.windows.controls.mediaelement(v=vs.90).aspx
저작자 표시 비영리 동일 조건 변경 허락
신고
posted by Town One townone
2013.05.27 10:34 Windows8/Windows Store App

현재 뮤직 플레이어를 만들고 있는데 한가지 문제점이 생겼다.

 

노래를 재생 하기 위해서는 MediaElement 인스턴스가 필요하다.

일단 MediaElement 에 노래 Urifile 을 넣어주고 Play() 메서드만 호출해 주면 재생하는건 아무 문제가 없다.

 

근데 문제는??

 

Element 가 모든 페이지 에서 공유가 되어야 한다는 것이다. 참고로 디자인 패턴에선 이걸 (싱글턴 패턴) singleton pattern 이라고 한다.

 

예를 하나 들어보자.

 

MainPage , MusicPlayingPage, 그리고 App bar 가 하나 있다고 치자.

 

MainPage 에는 MusicPlayingPage 로 이동하는 버튼이 있고 MusicPlayingPage 로 이동하면 노래가 자동으로 재생이 된다. 즉 MediaElement 를 사용하게 된다.

 

하지만 App bar 에서도 노래를 재생하거나 멈출 수 있다. 현재 재생되고 있는 노래를 멈추려면 아까 MusicPlayingPage 에서 재생된 그 MediaElement 에 접근이 가능해야 한다.

 

하지만 MusicPlayingPageApp bar 는 서로 다른 영역이다. 이렇게 서로 다른 두 영역에서 한가지 resource 를 사용할 수 있는 방법은 무엇이 있을까?!

 

일단 두가지 방법을 알아 내었다.

 

 

1. MediaElement 를 static 변수로 사용한다.

 

누구나 생각해 볼 수 있는 방법이다.. Windows store App 은 보통 처음 시작되면 App.xaml.csOnLaunched 가 호출되게 된다.

App 이 시작될 때 처음 호출되는 부분이므로 이곳에다 static 변수를 선언해 놓으면 App 이 종료될 때 까지는 계속 사용할 수가 있다.

 

나는 다음과 같이 만들어 보았다.

 

[App.caml.cs]

 

    public sealed partial class MainPage : Page
    {
        public static MediaPlayer player = null;
        public MainPage()
        {
            this.InitializeComponent();
            player = new MediaPlayer();
        }

        /// <summary>
        /// Invoked when this page is about to be displayed in a Frame.
        /// </summary>
        /// <param name="e">Event data that describes how this page was reached.  The Parameter
        /// property is typically used to configure the page.</param>
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            RootFrame.Navigate(typeof(RootPage), "");
        }
    }

 

[MediaPlayer.cs]

 

namespace MediaTest
{
    public class MediaPlayer
    {
        private MediaElement _media = null;
        public MediaElement Media
        {
            get;
            set;
        }

        public MediaPlayer()
        {
            Media = new MediaElement();
            Media.AudioCategory = Windows.UI.Xaml.Media.AudioCategory.BackgroundCapableMedia;
            //Media.AutoPlay = true;
        }

        public void Play()
        {
            Media.Play();
        }

        public void Stop()
        {
            Media.Stop();
        }

        public async void setMedia(StorageFile file)
        {
            var stream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
            Media.SetSource(stream, file.ContentType);
        }
    }
}

 

아까 말한대로 App.xaml.csMediaPlayer 라는 클래스의 인스턴스를 static 으로 생성해 줬다. MediaPlayer 는 그냥 예제용으로 만든 클래스 이다. MediaPlayer 클래스에는 실제로 MediaElement 가 위치해 있는 것이다.

 

그럼 이 MediaElement 를 사용해 보도록 하자.

 

[MusicPlayingPage.xaml.cs]

 

        private async void Button_Click_1(object sender, RoutedEventArgs e)
        {
            StorageFolder storageFolder = KnownFolders.DocumentsLibrary;
            StorageFile file = await storageFolder.CreateFileAsync("Music.mp3", CreationCollisionOption.OpenIfExists);
            MainPage.player.setMedia(file);
            MainPage.player.Play();
 
         }

 

MusicPlayingPage 에서는 간단히 버튼이 눌리면 음악 파일을 읽어와 stream 방식으로 재생해주고 있다.

노란색으로 하이라이트 된 부분을 보면 아까 static 으로 선언했던 player 변수를 사용하고 있다.

static 으로 선언이 되었기 때문에 어느 Page 에서든 접근이 가능하다.

 

App bar 에서 사용할 때도 저렇게 사용해 주면 된다.

 

근데 이렇게 하는건 뭔가 찜찜하다.. 잘못된 방법은 아니지만 뭔가 찜찜하다.. 그래서 MSDN을 찾아보니 아래와 같은 방법이 제시되어 있었다.

 

 

2. App.xaml 에 변수를 선언

 

기가막힌 방법이다. App.xaml 는 이미 static 하게 사용하도록 만들어져 있기 때문에 이곳에 선언을 해 두면 어디서든 사용이 가능하다.

 

 

<Application
    x:Class="MediaTest.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MediaTest">


    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>

                <!--
                    Styles that define common aspects of the platform look and feel
                    Required by Visual Studio project and item templates
                 -->

                <ResourceDictionary Source="Common/StandardStyles.xaml"/>
            </ResourceDictionary.MergedDictionaries>
            <MediaElement x:Name="localMediaElement"/>
        </ResourceDictionary>
    </Application.Resources>
</Application>

 

노란색 하이라이트를 보면 MediaElement를 다른 resource 들과 동일하게 선언해 놓은 것을 볼 수 있다.

이렇게 하면 소스코드와 마찬가지로 App.xaml 페이지가 호출 될 때 MediaElement 인스턴스가 생성이 된다. 사실 정확한건 아니다. 이건 내 직감일 뿐이다...

 

이제 선언을 했으니 저걸 불러다 사용해 보자.

 

 

        private async void Button_Click_1(object sender, RoutedEventArgs e)
        {
            StorageFolder storageFolder = KnownFolders.DocumentsLibrary;
            StorageFile file = await storageFolder.CreateFileAsync("01 봄바람.mp3", CreationCollisionOption.OpenIfExists);
 
            MediaElement media = (MediaElement)App.Current.Resources["localMediaElement"];
            var stream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
            media.SetSource(stream, file.ContentType);
            media.Play();
        }

 

노란색 하이라이트만 보자. 아까 등록한 resource 를 불러다쓰려면 저렇게 하면 된다. 다시 말하지만 현재 저 resourcestatic 하게 인스턴스 화 되어 있는 상태이다. 때문에 다른 페이지에서 저렇게 가져온다고 해서 새로 인스턴스가 생성되거나 하지 않는다. 레퍼런스만 가져오는 것이다.

 

근데 보면 저거 꼭 "App.xaml 에 선언해줘야 되는건가?" 라는 궁금증이 든다.

 

그래서 static resource 파일인 CommonStandardStyles.xaml 에도 선언을 해 줘봤다.

 

잘된다!

 

그럼 다시.

 

우리는 보통 StandardStyles 에다 필요한 선언을 하지 않는다. Microsoft 에서 Common 폴더 내에 있는건 왠만하면 건들지 말라고 권장하고 있기 때문이다. 그래서 보통 ResourceDictonary를 새로 하나 생성해서 사용하곤 한다.

 

그럼 새로 생성한 ResourceDictonary 에 변수를 선언해 줘도 static 하게 동작할까?

 

잘된다!!

 

하지만 새로 생성한 ResourceDictonaryApp.xaml 에서 StandardStyle.xamlmerge 해줘야 한다는 점.

 

[App.xaml]

 

<Application
    x:Class="MediaTest.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MediaTest">


    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>

                <!--
                    Styles that define common aspects of the platform look and feel
                    Required by Visual Studio project and item templates
                 -->

                <ResourceDictionary Source="Common/StandardStyles.xaml"/>
                <ResourceDictionary Source="CustomStyle.xaml"/>
            </ResourceDictionary.MergedDictionaries>
            <!--<MediaElement x:Name="localMediaElement"/>-->
        </ResourceDictionary>
    </Application.Resources>
</Application>

 

이 두가지 방법을 쓰면 싱글턴 패턴을 쓰는데 무리가 없을 것 같다.

 

좀 더 전문적인 글을 보기 위해선 아래 링크를 참고하자.

 

http://msdn.microsoft.com/en-us/library/ff650316.aspx

저작자 표시 비영리 동일 조건 변경 허락
신고
posted by Town One townone
2013.05.24 18:22 Windows8/Windows Store App
http://cafe.naver.com/mobilenjoy/13601

 

저작자 표시 비영리 동일 조건 변경 허락
신고
posted by Town One townone
2013.05.24 16:00 Windows8/Windows Store App

http://cafe.naver.com/metroapp/130

저작자 표시 비영리 동일 조건 변경 허락
신고
posted by Town One townone
2013.05.24 12:39 Windows8/Windows Store App
http://cafe.naver.com/metroapp/104

 

저작자 표시 비영리 동일 조건 변경 허락
신고
posted by Town One townone
2013.05.24 11:57 Windows8/WPF

출처 : http://rageworx.tistory.com/894

 

M$.NET/VS2005/C# 에서 USB camera 해상도 설정 관련 사항.

Developement 2010/06/09 10:19

초접사 USB cam 으로 찍은..

WPF 란걸 써야 하는 조건이라면 어쩔 수 없이 개발자들은 M$ 의 덩치크고 메모리킬러 인 .NET + C# 이라는 조건을 받아 들여야 할 것입니다.
WPF 란 이쁘고 화려한 UI 까지는 다 좋은데, 안타깝게도 이 방식은 제가 볼때 Layered Window 위에다 .NET 이 열심시 이미지와 각종 컴퍼넌트 등을 그리고 있는 걸 합니다.
또한 GDI+ 를 wrapping 한 듯한 rendering 속도를 보여 주는 걸로 보아 조금 답답한 면도 있구요.

일단 C# 선생은 제가 볼때 (절대 제 게인적인 생각입니다) 10년 전 부터 제가 써온 Delphi 가 채용하고 있는 Application Framework + 객체지향 개념과 java 등등이 잘 버무려져 있는 무거운 언어 입니다. 다른 점 이라면, WPF 라는 새로운 UI 개념이 탑재 되어 있다는 거겠지요.
Java 처럼 GC(가비지 콜렉터)가 있어서 new 를 볼 수는 있지만 delete 는 보이지 않습니다...
그래서 WPF + 조금 복잡한 application 이 탄생하면 메모리를 한 100MB 는 기본으로 쓰는 듯 합니다.

잡설을 일단 접고, 현재 C# 에서 DirectX 의 DirectShow 를 쓰려면 OpenSource 인 DShow 라이브러리를 사용해야 합니다.
이 방식은 WPF 의 윈도우 핸들에서는 사용할 수 없으며, 표준 window 에만 적용이 될 수 있습니다.

C# 에서는 C/C++ 과는 달리 #include .. 대신에 using namespace 를 사용합니다. 
(이 using 은 Delphi 에서 이미 uses 라는 표준 Pascal 문법과 매우 유사하다는 건 .. 저만의 생각이겠죠?)
제작하는 project root 에 DShow 라이브러리를 넣고 using DShowLibrary; 와 using System.Runtime.InteropServices.ComTypes; 를 선언 함 으로서 DShow 를 사용할 준비가 완료 됩니다.

DShow 를 쓰려면 일단 해당 클래스가 다음 클래스를 상속받는 구조가 되어야 합니다.
IDisposable
ISampleGrabberCB
IDisposable 은 preview 를 위한 윈도우 컨트롤 후 메모리를 날리기 위해 필요한 .Dispose(); 를 위해 필요하고,
ISampleGrabberCB 는 DShow 에서 기정의 한 이미지 및 동영상 캡쳐를 위한 SampleCB, BufferCB 때문에 필요한 부분 입니다.

이제 DShow 로 USB camera 를 생성 하기 위해서는 다음 사항이 먼저 class 내에 정의 되어 있어야 합니다.
        private IBaseFilter _capFilter; 
        private IGraphBuilder _graphBuilder;
        private ICaptureGraphBuilder2 _captureGraphBuilder; 
        private ISampleGrabber _sampleGrabber;
        private IMediaEventEx _mediaEventEx;
        private IVideoWindow _videoWindow;
        private IBaseFilter _baseGrabFilter;
        private IAMStreamConfig _streamConfig;
위 사항은 기본적으로 USB camera 의 영상을 가져오고 캡쳐 하기 위해 필요한 인터페이스들 이 되며, 이는 모두 COM 에서 얻어 오는 구조가 됩니다.

DShow 에서 가장 처음 알아야 하는 것은 바로 USB 영상 장비의 Index 입니다.
이 USB 장비들은 DShow 내의 DsDevice 클래스로 부터, GetDeivcesCat() 함수로 얻어 올 수 있습니다.
간단히 각 장치를 알아 와서 뭔가 한다면 다음 처럼 만들 수 있겠습니다.
foreach (DsDevice ds in DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice))
{
    deviceNames.Add(ds.Name);
}
C# 부터는 foreach() 가 있어서 for() 대신에 유용하게 쓸 수 있는 것이 있어서 단순 목록은 물론, 검색 등에 다양하게 사용이 가능합니다.
각 장치의 순서가 바로 그 장치의 index 가 되며, 이중 필요한 장비를 최기화 한다면 다음 과 같이 할 수 있겠습니다.
_capFilter = CreateFilter(_deviceIndex);
if (null == _capFilter) return S_FALSE;
USB 카메라를 처음 접근 하기 위해서는 CaptureFilter를 먼저 생성해야 합니다.
그런다음, IGraphBuilder 인터페이스를 통해 새로운 필터그래프를 하나 만들어야 합니다.
_graphBuilder = (IGraphBuilder)new FilterGraph();
if (null != _graphBuilder)
{
    ...................
}
새로운 클래스 나 메서드 등을 만들때 외에 일반적인 type-cast 를 한다면, C# 에서는 C/C++ 처럼 type-cast 를 쓸 수도 있지만 "as" 라는 것이 있어서 특정 캐스팅을 다음과 같이 할 수도 있습니다.
_mediaControl        = _graphBuilder as IMediaControl;
이건 마치 VisualBasic 같은 느낌도 듭니다 .. -_-;;
이제 _graphBuilder 가 생성 되었다면 각 중요한 아이들을 잡아 줘야 겠죠.
다음 처럼 할 수 있습니다.
_captureGraphBuilder = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();
_sampleGrabber       = (ISampleGrabber)new SampleGrabber();
_mediaControl        = _graphBuilder as IMediaControl;
_videoWindow         = _graphBuilder as IVideoWindow;
_mediaEventEx        = _graphBuilder as IMediaEventEx;
_baseGrabFilter      = _sampleGrabber as IBaseFilter;
이걸로 끝이면 참 편리 하겠지만 DShow 는 좀 더 많은 일을 해야 합니다 .. -_-;;;
다음으로 필요 한 것은 _captureGraphBuilder 에 이미 만들어진 _graphBuilder (FilterGraph 임) 를 지정해 줘야 합니다.
hr = _captureGraphBuilder.SetFiltergraph(_graphBuilder);
DsError.ThrowExceptionForHR(hr);
hr 은 C# 에 HRESULT 형이 없으므로 그냥 int 로 선언 해 쓰면 됩니다.
물론 C/C++ 에서는 HRESULT 를 사용해 주시는게 맞습니다만..
DsError 클래스는 DShow 에서 발생하는 오류를 HR 값을 가지고 Throw Exception 처리를 해 줍니다.
try - catch - finally 라는 개념을 잘 안쓰던 C/C++ 개발자라면 조금 생소한 부분일 수 도 있겠습니디만 ..
이 try -- catch 부분은 80386 CPU 부터 CPU 상에서 지원되는 몇가지 기능을 활용하는 훌륭한 기능 입니다. 나온지 꽤 오래 되었지만 쓸 수 있는 언어가 많지 않았지요.

이제 다음으로 필요한 건, _captureGraphBuilder 에 지정한 _graphBuilder 에 또 다시 제일 처음 생성한 _capFilter 를 이름을 붙여 집어 넣어 줘야 합니다 ... 귀찮지만 해 줘야 합니다 ... 아놔 ...
hr = _graphBuilder.AddFilter(_capFilter, "video device");
DsError.ThrowExceptionForHR(hr);
붙이는 이름은 마음대로 넣어도 됩니다만, 나중에 이름으로 찾아 써야 할 때를 고려 한다면 좋게 지어 넣어 주는 센스를 가지는 것 또한 나쁘진 않습니다.
물론 C# 과 .NET 조합은 모든 문자열이 UniCode 임을 고려 해야 합니다. C++ 에서 LPWStr 형과 동일 합니다.

이쯤 오면 대부분 다음엔 바로 _captureGrabber 를 만들고 Stream render 를 설정해 버리는 예제 코드들로 인터넷에 도배가 되어 있을 겁니다.
하지만 이래서는 연결된 USB cam 에 대한 정보를 내가 먼저 알고 뭔가 하기란 어려워 지게 되죠.
그래서!

바로 이 시쯤에서 _streamConfig 을 설정하고, 이로부터 장치가 지원하는 해상도를 알아 오도록 합니다.
가장 중요한 것은 _streamConfig 을 _captureGraphBuilder 로 부터 찾아내 와야 합니다.
COM 에서 가장 많이보는 FindInterface() 함수를 사용합니다.
또한 C# 에서는 IntPtr 이란 것이 있어서 포인터의 주소를 얻어오는 독특한 구조를 가끔 사용함으로 다음 예제에서 처럼 기정의된 구조에 맞춰 사용해 줘야 하는 점도 있습니다.
일단 StreamConfig 을 가져오는 부분이 빈번하게 발생하는 걸 고려 해서 간단히 함수를 만들어 보면 다음과 같은 구조로 되더군요. 물론 더 좋은 방법이 있다는걸 생각해 보셔야 합니다.
01 private IAMStreamConfig GetStreamConfig()
02 {
03     Guid IID_IAMStreamConfig = typeof(IAMStreamConfig).GUID;
04     IAMStreamConfig retSC = null;
05     object pObj = null;
06     int hr = -1;
07  
08     hr = _captureGraphBuilder.FindInterface(PinCategory.Capture,
09                                             MediaType.Video,
10                                             _capFilter,
11                                             IID_IAMStreamConfig,
12                                             out pObj);
13     DsError.ThrowExceptionForHR(hr);
14  
15     if (pObj != null)
16     {
17         retSC = pObj as IAMStreamConfig;
18     }
19  
20     return retSC;
21  
22 }
자, 이제 지원하는 해상도 정보를 얻어 오려면 다음 루틴 처럼 만들 수 있습니다.
01 if(null == _streamConfig)
02     _streamConfig = GetStreamConfig();
03  
04 int iCount, iLen, iSize = 0;
05  
06 if (_streamConfig != null)
07 {
08     hr = _streamConfig.GetNumberOfCapabilities(out iLen, out iSize);
09     DsError.ThrowExceptionForHR(hr);
10  
11     if (iLen > 0)
12     {
13         for (iCount = 0; iCount < iLen; iCount++)
14         {
15             AMMediaType aMM = new AMMediaType();
16  
17             IntPtr pSCC = IntPtr.Zero;
18             pSCC = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(VideoStreamConfigCaps)));
19             VideoStreamConfigCaps aSCC = new VideoStreamConfigCaps();
20  
21             hr = _streamConfig.GetStreamCaps(iCount, out aMM, pSCC);
22             DsError.ThrowExceptionForHR(hr);
23             aSCC = (VideoStreamConfigCaps)Marshal.PtrToStructure(pSCC, typeof(VideoStreamConfigCaps));
24  
25             VideoInfoHeader pVIH = new VideoInfoHeader();
26             Marshal.PtrToStructure(aMM.formatPtr, pVIH);
27             // 이제 여기에서 pVIH 에 있는 bmiHeader 를 보고 해상도와 지원되는 plane, bpp 등을 알아 옵니다.
28             // 그리고 다음 코드를 ...
29  
30             Marshal.FreeCoTaskMem(pSCC);
31             DsUtils.FreeAMMediaType(aMM);
32         }
33     }
34 }

처음 C# 을 쓸대 포인터 에서 구조체/클래스 간으로 전환 하는 부분이 적응이 매우 어려웠었습니다.
Marshal 이라는 게 C# 에서 참 중요한 부분인 듯 하게 느껴지는건 이걸 처음 C/C++ 코드에서 가져올때 인 듯 하네요.
위 코드를 통해서 VideoInfoHeader 를 이용한 지원 해상도와 정보를 알아 왔으니 이젠 해상도를 설정 할 차례 입니다.
해상도 설정은 _streamConfig 에 하게 되며, _streamConfig 에 지정된 해상도는 알아서 _sampleGrabber 에 적용되게 됩니다.

코드를 보면 ...
01 if (null != _streamConfig)
02 {
03     int hr = -1;
04  
05     AMMediaType pDefaultMMT = new AMMediaType();
06  
07     hr = _streamConfig.GetFormat(out pDefaultMMT);
08     DsError.ThrowExceptionForHR(hr);
09  
10     VideoInfoHeader pDefaultVIH = (VideoInfoHeader)Marshal.PtrToStructure(pDefaultMMT.formatPtr, typeof(VideoInfoHeader));
11  
12     foreach(AMMediaType pMMT in _videoResolutionList)
13     {
14         VideoInfoHeader pVIH = (VideoInfoHeader)Marshal.PtrToStructure(pMMT.formatPtr, typeof(VideoInfoHeader));
15         if((pVIH.BmiHeader.Width == width) && (pVIH.BmiHeader.Height == height) &&
16             (pVIH.BmiHeader.Planes == pDefaultVIH.BmiHeader.Planes)&&
17             (pVIH.BmiHeader.Compression == pDefaultVIH.BmiHeader.Compression))
18         {
19             hr = _streamConfig.SetFormat(pMMT);
20             DsError.ThrowExceptionForHR(hr);
21             retBl = true;
22         }
23     }
24     DsUtils.FreeAMMediaType(pDefaultMMT);
25 }

참고 : 위 코드에서 _videoResolutionList는 List<AMMediaType> 객체로 만들어 두었습니다.
나름 안전한 방법을 생각해서 만든 코드이라 복잡합니다만 , 핵심은 바로 _stramConfig.SetFormat(); 함수 입니다. SetFormat() 을 적용할 수 있는 시점은 바로 _captureGraphBuilder 에 RenderStraem() 을 지정하기 전 입니다.
RenderStream() 을 지정하고 나서는 _streamConfig 에 SetFormat() 을 하게 되면 잘못된 미디어 오류가 발생하게 됩니다.

그래서 RenderStream() 을 지정하기 전에 반드시 _streamConfig 에 먼저 해상도 조절을 해 두어야지만 적용이 가능하게 됩니다.

이 부분에 대해서는 구글링을 아무리 해도 나오는 게 없었던지라 ..
노가다 뛰어서 알아내어야 하더군요 .. OTL...
혹시나 해서 포스팅 해 봅니다.
저작자 표시 비영리 동일 조건 변경 허락
신고
posted by Town One townone
2013.05.24 11:18 Windows8/Windows Store App
http://www.microsoft.com/visualstudio/kor/downloads#d-2012-express

 

저작자 표시 비영리 동일 조건 변경 허락
신고
posted by Town One townone
2013.05.24 11:13 Windows8/Windows Store App

KOR : http://msdn.microsoft.com/ko-kr/library/windows/apps/windows.media.mediacontrol

EN : http://msdn.microsoft.com/en-us/library/windows/apps/windows.media.mediacontrol.aspx

 

저작자 표시 비영리 동일 조건 변경 허락
신고
posted by Town One townone