WPF - XDL Tutorial

XDL VideoView 활용 두번째

(piXoneer XDL Tutorial)

 

 

 

 

 

 

NXVideoView를 활용하여 동영상 플레이어를 구현해 봅니다.

기본적인 동영상 플레이어 기능을 수행합니다.

 

 

2019. 04.

 

 

목차

XDL VideoView 활용 두번째... 1

1    사용하기... 3

1.1    NXVideoView 이용한 예제 프로그램 만들기... 3

1.2    Driver복사하기... 4

1.3    메뉴 생성하기... 5

1.4    NXVideoView컨트롤 올리기... 6

1.5    동영 열기 기능... 6

 

 

 

 

1     사용하기

 

1.1    NXVideoView를 이용한 예제 프로그램 만들기

1.1.1     Visual Studio 2015을 실행한다.

1.1.2     메뉴 [파일]-[새로 만들기]-[프로젝트]를 선택한다.

1.1.3     [새 프로젝트] 대화상자에서 왼쪽의 템플릿 창에서 “Visual C#”을 선택하고, 대화상자 중간의 목록에서 “WPF 응용 프로그램을 선택한다.

사용자가 원하는 경로를 선택한 다음 프로젝트 이름을 “XDL_VideoView2” 으로 입력하고 [새 프로젝트] 대화상자의 확인버튼을 클릭한다. 이 문서에서는 대화상자 오른쪽 아래에 있는 “솔루션용 디렉터리 만들기”는 선택하지 않겠다. “확인” 버튼을 누르면 프로젝트가 기본적으로 생성되고, 화면에 Window을 디자인할 수 있는 화면이 뜬다. 만약 아래와 같은 Window 창이 생성되지 않으면, [솔루션 탐색기] 창에서 MainWindow.xaml”를 마우스 더블클릭을 하여 창을 연다.

 

1.1.4     솔루션 탐색기의 프로젝트 하부의 [참조]의 오른쪽 마우스 클릭을 통해 [참조추가]를 선택한다.

 

 

1.1.5     [찾아보기]탭으로 이동한 후 “C:\Pixoneer\XDL1.2\bin\”경로로 이동한다. Ctrl키를 누른 채 “NXDL.dll, “NXDLgr.dll”, “NXDLsm.dll”, “NXVideo.dll”을 선택한 후 “확인”버튼을 선택한다.

 

1.1.6  솔루션 탐색기의 프로젝트 하부의 [참조]항에 NXDL, LXDLgr, NXDLsm, NXVideo가 추가되었음을 확인한다

1.1.7     NXVideo를 활용하기 위해 MainWindow.xaml 창에서 namespace를 다음과 같이 추가한다.

 

1.2    Driver복사하기

Driver는 현재 데모 버전에서는 설치된 경로로부터 실행 경로 하부로 직접 복사하여 넣어야 한다. 차기 버전은 복사를 하지 않아도 실행될 수 있도록 구성된다.

 

1.2.1     XDL 라이브러리가 설치된 경로(C:\Pixoneer\XDL1.2\bin)로 이동한다.

 

1.2.2     VDDrivers폴더를 통째로 복사하여 현재 프로젝트의 “…..\XDL_VideoView2\bin\Debug”폴더 하부에 복사하여 넣는다.

1.2.3     F5키를 눌러 프로그램을 실행하면 다음과 같이 구성된다.

 

 

1.3    메뉴 생성하기

1.3.1      MainWindow.xaml창에서 기본으로 생성된 Grid 레이아웃에 Grid.RowDefinition을 이용하여 세 개의 Row을 생성한다. Menu를 첫 번째 Cell에 배치하고 MenuItem 항목을 추가하여 [File] [Open]을 생성한다. (자세한 메뉴 생성에 대한 설명은 XDL VideoView1 Tutorial을 참고한다.)

 

<Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="30"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="40"/>
        </Grid.RowDefinitions>

        <Menu Grid.Row="0">
            <MenuItem Header="_FIle" Margin="5,5,4,5">
                <MenuItem x:Name="openFileMenuItem" Header="_Open"/>
            </MenuItem>
        </Menu>
</Grid>

 

 

 아래의 표를 참고하여 메뉴를 생성한다.

 

Control Type

Header

Name

MenuItem

_File

 

MenuItem

_Open

openFileMenuItem

 

 

1.4    Player컨트롤 생성하기

1.4.1     동영상 플레이어를 위해 “Play”, “Pause”, “Stop”기능과 진행률을 표시하는 스크롤 기능을 구현한다. 세 번째 RowGrid에 배치하고 이 Grid를 네 개의 Column으로 나누어 각각에 맞는 기능을 배치한다. 차례대로 (1) 에는 “Play” 버튼, (2) 에는 “Pause” 버튼, (3) “Stop” 버튼이 배치될 것이다.

 

 

샘플코드에서 이미지를 다운 받아 [속성] 창에 브러시속성을 통해 알맞은 공간에 배치한다. 작업을 완료하면 아래와 같은 디자인을 얻을 수 있다. (자세한 설명은 샘플코드를 참고한다.)

 

 

1.5    NXVideoView컨트롤 추가하기

1.5.1     Grid 레이아웃 내부에서 두 번째 CellGrid를 배치하고 WindowsFormsHost 컨트롤을 도구상자로부터 끌어서 생성하거나 XAML 창에 입력하여 생성한다. 이는 Window formsHosting 해주는 개체이며 Window Forms Control을 사용할 때 이용된다. (WindowFormIntegrationSystem.Window.Forms을 어셈블리에 대한 참조 추가를 한다.)

1.5.2     앞서 추가한 namespacenxVideo를 이용하여 NXVideoView컨트롤을 불러온다. NXVideoView의 이름(Name) nxVideoView1으로 한다. 또한 NXVideoOverlay컨트롤을 NXVideoView 컨트롤 위에 올려놓기 위해 불러오는 작업을 한다. XNVideoOverlay의 이름(Name)nxVideoLayerOverlay1이라고 한다.

 

<Grid Grid.Row="1">
       <WindowsFormsHost Grid.Column="0" Margin="3,0,3,3">
             <nxVideo:NXVideoView x:Name="nxVideoView1">
                 <nxVideo:NXVideoView.Controls>
                   <nxVideo:NXVideoLayerOverlay x:Name="nxVideoLayerOverlay1"/>
                 </nxVideo:NXVideoView.Controls>
             </nxVideo:NXVideoView>
        </WindowsFormsHost>
</Grid>

 

1.5.3     [F5]키를 눌러 프로그램을 실행한다. 아래와 같이 NXVideoView컨트롤이 존재하는 프로그램이 실행된다.

 

 

1.6    동영상 열기 기능 구현

1.6.1     Window창에서 Menu[File]-[Open]을 더블 클릭하여 함수를 자동 생성한다.

private void openFileMenuItem_Click(object sender, RoutedEventArgs e)
{

}

 

1.6.2     NXVideo객체들을 사용하기 위해서 다음과 같이 NXDL, NXVideo 네임스페이스를 추가한다.

using Pixoneer.NXDL;
using Pixoneer.NXDL.NXVideo;

 

1.6.3     NXVideoView구현시 필요한 XVideoIO, XVideo, XVideoChannel객체를 선언한다.

public partial class MainWindow : Window
{
    enum VideoAction { STOP, PLAYING, PAUSED }
    struct VideoState
    {
       public XVideo video;            // 파일이나 네트워크로부터 입력되는 
// 스트리밍데이터를 제어하는 기능을 수행할 객체 선언
       public XVideoChannel videoChannel;  // 동영상 개체에 포함된 채널 객체 선언
       public string videoFilePath;        // 동영상 파일 경로
       public VideoAction action;          // 비디오 플레이 상태를 정의하는 객체 선언 

     }
     private XVideoIO m_videoIO = null;
     private VideoState VS;                 // 비디오 상태를 관리하는 객체 선언

 

1.6.4     Winodow XVideoIO의 객체 생성 및 VideoState에 대한 초기화를 수행한다. 또한 프로그램 종료시, 메모리 관리 등을 위해 NXVideoView컨트롤의 초기화를 수행한다.

public MainWindow()
{
       InitializeComponent();
       m_videoIO = new XVideoIO();  // VideoIO를 생성

       VideoInit();
       nxVideoLayerOverlay1.LayerVisible = true;

}

private void VideoInit()
{
       // VideoState의 초기화
       VS.video = null;
       VS.videoChannel = null;
       VS.videoFilePath = string.Empty;
       VS.action = VideoAction.STOP;
}

private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
        // 동영상 채널 정보 초기화
        nxVideoView1.ResetVideoChannel();

        if (VS.video != null)
        {
            // 동영상 객체 Close
            VS.video.Close();
            VS.video = null;
         }

         if (m_videoIO != null)
         {
            // 동영상 입출력 객체 Dispose
            m_videoIO.Dispose();
         }
}

 

1.6.5     [File]-[Open]을 눌렀을 때 생성될 Open 대화상자와 선택된 파일에 대한 XVideo객체를 생성한다. 또한, XVideo객체에 실제 스트리밍을 담당하는 XVideoChannel객체를 활성화(Activate) 시켜 Frame을 내부적으로 생성하도록 지시한다.

private void openFileMenuItem_Click(object sender, RoutedEventArgs e)
{
      // 새로운 파일 Open을 수행한다.
      OpenFileDialog openFileDialog = new OpenFileDialog();
      openFileDialog.Filter = "TS file(*ts)|*.ts||";
      openFileDialog.RestoreDirectory = true;

Nullable<bool> result = openFileDialog.ShowDialog();
      if (result != true) return;

      string videoPath = openFileDialog.FileName;

      // 동영상 파일의 존재 유무 체크
      if (System.IO.File.Exists(videoPath) == false)
      {
          MessageBox.Show(this, "해당 경로에 영상이 존재하지 않습니다.", "오류");
          return;
       }

      // 파일 경로를 저장한다.
      VS.videoFilePath = videoPath;

      // 동영상의 재생상태가 중지가 아닐 경우 동영상 재생 중지
      OnStop();

      // 동영상 스트리밍 환경을 생성시킨다.
      OnOpen();

      // 동영상을 Play 시킨다.
      OnPlay();
}

 

1.6.6     OnOpen함수에 동영상을 재생하기 위해서 VS.videoFilePath에 설정된 파일 경로를 통하여 NXVideoView컨트롤을 XVideoChannel로 초기화 시킨다.

// 동영상 파일 열기
public void OnOpen()
{
    try
   {
    string strError = null;
    // 동영상 스트림 정보 가져오기
    VS.video = m_videoIO.OpenFile(VS.videoFilePath, "XFFMPDRIVER", out strError);

        if (VS.video == null)
        {
           MessageBox.Show(this, "동영상 재생에 실패하셨습니다. 파일을 확인해주십시오.", "파일 열기");
           return;
         }

    // 다중 채널을 가진 동영상 객체의 Channel 인덱스
    int nIdxChannel = 0;

    // 동영상 뷰에 재생할 동영상 채널의 설정
    nxVideoView1.SetVideoChannel(VS.video, nIdxChannel);

    // 입력 인덱스에 해당하는 Channel 가져오기
    VS.videoChannel = VS.video.GetChannel(nIdxChannel);

    // GetChannel에 실패할 경우 Null 객체가 return되며, 그에 대한 예외처리
    if (VS.videoChannel == null)
    {
           MessageBox.Show(this, "동영상 재생에 실패하였습니다. 파일을 확인해 주십시오.", "파일 열기");
           return;
     }

      // 동영상 객체에 포함된 Channel 객체 중 해당 Channel 객체를 활성화
      //활성화된 객체만 스트리밍이 수행
      VS.videoChannel.Activate();

}

     catch (Exception ex)
     {
        Console.WriteLine(ex);
        MessageBox.Show(this, "재생 실패!", "동영상");
        VS.action = VideoAction.STOP;
     }
}

 

1.6.7     동영상을 재생시키도록 지시하는 OnPlay, Play되고 있는 도중에 비디오를 멈추고 초기화 시키는 OnStop, Play되고 있는 도중에 중지시키는 OnPause함수를 구현한다.

private void OnPlay()
{
      if (VS.action == VideoAction.PAUSED)  // 동영상이 중지 상태가 아닐경우
      {
         VS.videoChannel.Resume();        // 동영상 채널 Resume
         VS.action = VideoAction.PLAYING;
      }
      else if (VS.action == VideoAction.STOP) // 동영상이 중지 상태일 경우
      {
         // 동영상 Channel을 처음부터 재생하다록 Play 신호 설정
         VS.videoChannel.Play();
         VS.action = VideoAction.PLAYING;
      }
}

private void OnPause()
{
      if (VS.action == VideoAction.PLAYING)
      {
         VS.videoChannel.Pause();         // 동영상 채널 Pause
         VS.action = VideoAction.PAUSED;
      }

 }

private void OnStop()
{
      if (VS.videoChannel != null)
      {
          // 재생 Frame Buffer를 삭제
          VS.videoChannel.ClearFrameBuffer();
          // 동영상 재생 스크린을 갱신한다.
nxVideoView1.RefreshScreen();
          // 동영상 재생 중지
          VS.videoChannel.Stop();
      }

      // 동영상 채널 정보 초기화
      nxVideoView1.ResetVideoChannel();

      if (VS.video != null)
      {
           // 동영상 객체 Close
           VS.video.Close();
           VS.video = null;
      }

      VS.action = VideoAction.STOP;
}

 

1.6.8     Window 창에 있는 [], [], []을 눌렀을 때 수행되는 기능을 구현한다. [], [], [] 버튼의 [속성]창에서 클릭 이벤트를 생성한다.

private void playButton_Click(object sender, RoutedEventArgs e)
{
      // 비디오가 Stop인 상태인 경우 다시 비디오를 저장된 파일 경로로부터 Open해서 설정한다.
      if (VS.action == VideoAction.STOP)
      {
           OnOpen();

       }

       // 설정된 비디오를 Play 한다.
       OnPlay();
}

private void pauseButton_Click(object sender, RoutedEventArgs e)
{
       // Play 되고 있는 비디오를 Pause 시킨다.
       OnPause();
}

private void stopButton_Click(object sender, RoutedEventArgs e)
{
       // Play 되고 있는 비디오를 Stop 시킨다.
       OnStop();
}

 

1.6.9      [F5]키를 눌러 프로그램을 실행한다. 홈페이지에서 샘플영상을 다운로드 한다. [File]-[Open]메뉴를 눌러 stream.ts파일을 연다. [], [], [] 버튼을 눌러 기능을 확인한다.