WPF – XDL Tutorial

XDL VideoView È°¿ë ¼¼¹ø°

(piXoneer XDL Tutorial)

 

 

 

 

 

 

 NXVideoView¸¦ È°¿ëÇÏ¿© µ¿¿µ»ó Ç÷¹À̾ ±¸ÇöÇØ º¾´Ï´Ù.

Timer¸¦ ÅëÇØ ÃÑ Frame¼ö¿Í ÇöÀç µµ½ÃµÇ´Â FrameÁ¤º¸¸¦ ȹµæÇÏ¿©

Slider¸¦ ÅëÇØ Á¤º¸¸¦ ¾÷µ¥ÀÌÆ®ÇÏ¿© µµ½ÃÇÏ°Ô µË´Ï´Ù.

 

 

 2019. 04.

 

 

¸ñÂ÷

XDL VideoView È°¿ë ¼¼¹ø°... 1

1    »ç¿ëÇϱâ... 1

1.1    Play ½Ã°£ ÄÁÆ®·Ñ ³Ö±â... 1

1.2    Slider µ¿±âÈ­... 1

 

 

 

 

1     »ç¿ëÇϱâ

º» Æ©Å͸®¾óÀ» °øºÎÇϱâ Àü¿¡ ¸ÕÀú ¡°XDL VideoView È°¿ë µÎ¹ø°¡±¸¦ ¸ÕÀú ¼±ÇàÇϽñ⠹ٶø´Ï´Ù. XDL VideoView È°¿ë µÎ¹ø°¿¡ À̾ ÁøÇàÇÕ´Ï´Ù.

1.1    Play ½Ã°£ ÄÁÆ®·Ñ ³Ö±â

1.1.1     µðÀÚÀÎâ¿¡¼­ label°ú Slider¸¦ ÀÌ¿ëÇØ ´ÙÀ½ ¾Æ·¡¿Í ±×¸² °°ÀÌ µðÀÚÀÎÇÑ´Ù. Ç¥¸¦ Âü°íÇÏ¿© ¡°currentTimeLabel¡±À» (1)¿¡ ±×¸®°í ¡°playControlSlider¡±À» (2)¿¡, ¡°totalTimeLabel¡±À» (3)¿¡ ÀÔ·ÂÇÑ´Ù. (ÀÚ¼¼ÇÑ UI µðÀÚÀο¡ ´ëÇؼ­´Â »ùÇÃÄڵ带  ÂüÁ¶ÇÑ´Ù.)

 

 

Number

Control Type

Name

(1)

Label

currentTimeLabel

(2)

Slider

palyControlSlider

(3)

Label

totalTimeLabl

 

 

1.2    Slider µ¿±âÈ­

1.2.1     Windowâ¿¡¼­ MenuÀÇ [File]-[Open]À» ´õºí Ŭ¸¯ÇÏ¿© ÇÔ¼ö¸¦ ÀÚµ¿ »ý¼ºÇÏ°í µÎ ¹ø° ¸Å´º¾óÀ» ±âÁØÀ¸·Î ´ÙÀ½°ú °°ÀÌ ±â´ÉÀ» Ãß°¡ÇÑ´Ù. Timer¸¦ Ãß°¡ÇÏ°í FrameÁ¤º¸¸¦ À§ÇÑ TotalFrame°ú CurrentFrameÀ» ¼³Á¤ÇÑ´Ù.

 

public partial class MainWindow : Window
{
    enum VideoAction { STOP, PLAYING, PAUSED }
    struct VideoState
    {
       public XVideo video;            // ÆÄÀÏÀ̳ª ³×Æ®¿öÅ©·ÎºÎÅÍ ÀԷµǴ 
// ½ºÆ®¸®¹Öµ¥ÀÌÅ͸¦ Á¦¾îÇÏ´Â ±â´ÉÀ» ¼öÇàÇÒ °´Ã¼ ¼±¾ð
       public XVideoChannel videoChannel;  // µ¿¿µ»ó °³Ã¼¿¡ Æ÷ÇÔµÈ Ã¤³Î °´Ã¼ ¼±¾ð
       public string videoFilePath;        // µ¿¿µ»ó ÆÄÀÏ °æ·Î
       public VideoAction action;          // ºñµð¿À Ç÷¹ÀÌ »óŸ¦ Á¤ÀÇÇÏ´Â °´Ã¼ ¼±¾ð
public long currentFrame;              // Àç»ýÁßÀÎ µ¿¿µ»óÀÇ ÇöÀç ÇÁ·¹ÀÓ À§Ä¡
       public long totalFrame;                // µ¿¿µ»ó Àüü ÇÁ·¹ÀÓ ¼ö  
 

     }
     private XVideoIO m_videoIO = null;
     private VideoState VS;                 // ºñµð¿À »óŸ¦ °ü¸®ÇÏ´Â °´Ã¼ ¼±¾ð

private System.Threading.Timer m_timer;    // Àç»ý ÄÁÆ®·Ñ ¹Ù µ¿ÀÛÀ» À§ÇÑ Å¸À̸Ó
private object m_lockCurFrame = new object();   
// Àç»ý ÄÁÆ®·Ñ ¹Ù¿ÍÀÇ µ¿±âÈ­¸¦ À§ÇÑ Lock °´Ã¼

 

1.2.2     Timer¸¦ »ý¼ºÇÏ°í TotalFrame°ú CurrentFrame¸¦ ÃʱâÈ­ ½ÃŲ´Ù.

public MainWindow()
{
       InitializeComponent();
       m_videoIO = new XVideoIO();  // VideoIO¸¦ »ý¼º

       VideoInit();
       nxVideoLayerOverlay1.LayerVisible = true;

// Àç»ý ÄÁÆ®·Ñ ¹Ù µ¿ÀÛÀ» À§ÇÑ Å¸ÀÌ¸Ó »ý¼º
       m_timer = new System.Threading.Timer(timer_Tick);

       // ŸÀÌ¸Ó ¿É¼Ç º¯°æ
       m_timer.Change(System.Threading.Timeout.Infinite, 
System.Threading.Timeout.Infinite);
}

private void VideoInit()
{
       // VideoStateÀÇ ÃʱâÈ­
       VS.video = null;
       VS.videoChannel = null;
       VS.videoFilePath = string.Empty;
VS.totalFrame = 0;
       VS.currentFrame = 0;

       VS.action = VideoAction.STOP;
}

 

1.2.3     OnOpen ÇÔ¼ö¿¡ TotalFrameÀ» ¾ò¾î VideoState¿¡ ÀúÀåÇÑ´Ù.

// µ¿¿µ»ó ÆÄÀÏ ¿­±â
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();

      // µ¿¿µ»óÀÇ Fram Á¤º¸¸¦ ¾ò¾î¿À±â
      VS.totalFram = VS.videoChannel.GetNumFramesVideo();

}

     catch (Exception ex)
     {
        Console.WriteLine(ex);
        MessageBox.Show(this, "Àç»ý ½ÇÆÐ!", "µ¿¿µ»ó");
        VS.action = VideoAction.STOP;
     }
}

 

1.2.4     OnStop ÇÔ¼ö¿¡ ¿¡ currentFrameÀ» ÃʱâÈ­ ½ÃŲ´Ù.

public void OnStop()
{
    if (VS.videoChannel != null)
    {
        // Àç»ý Frame Buffer¸¦ »èÁ¦
        VS.videoChannel.ClearFrameBuffer();
        // µ¿¿µ»ó Àç»ý ½ºÅ©¸°À» °»½ÅÇÑ´Ù.
        nxVideoView1.RefreshScreen();
        // µ¿¿µ»ó Àç»ý ÁßÁö
        VS.videoChannel.Stop();
        VS.videoChannel = null;
    }

    // µ¿¿µ»ó ä³Î Á¤º¸ ÃʱâÈ­
    nxVideoView1.ResetVideoChannel();

    if (VS.video != null)
    {
        // µ¿¿µ»ó °´Ã¼ Close
        VS.video.Close();
        VS.video = null;
    }

VS.currentFrame = 0;
    VS.action = VideoAction.STOP;
}

 

1.2.5     [File]-[Open] ¹öÆ°À» ´­·¶À» ¶§ ±â´ÉÀ» ¾÷µ¥ÀÌÆ® ½ÃŲ´Ù.

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();
 
// µ¿¿µ»ó »óŸ¦ ¾÷µ¥ÀÌÆ® ½ÃÅ°±â À§ÇØ Timer¸¦ ÀÛµ¿ ½ÃŲ´Ù. 100msec°£°ÝÀ¸·Î ¼³Á¤ÇÑ´Ù.
     OnTimer();

// PlayµÇ´Â ½Ã°£ Á¤º¸¸¦ µµ½ÃÇϱâ À§ÇØ Timer¼³Á¤°ú Slider¿Í LabelÀ» ÃʱâÈ­ ÇÑ´Ù. 
     InitSliderLabel();


     // µ¿¿µ»ó ½ºÆ®¸®¹Ö ȯ°æÀ» »ý¼º½ÃŲ´Ù.
     OnOpen();
 
     // µ¿¿µ»óÀ» Play ½ÃŲ´Ù.
     OnPlay();
}

 

1.2.6     [¢º], [¡«], [¡á] ¹öÆ°À» ´­·¶À» ¶§ ±â´ÉÀ» ¾÷µ¥ÀÌÆ® ½ÃŲ´Ù.

private void playButton_Click(object sender, RoutedEventArgs e)
{
    // ºñµð¿À°¡ StopÀÎ »óÅÂÀÎ °æ¿ì ´Ù½Ã ºñµð¿À¸¦ ÀúÀåµÈ ÆÄÀÏ °æ·Î·ÎºÎÅÍ OpenÇؼ­ ¼³Á¤ÇÑ´Ù. 
    if (VS.action == VideoAction.STOP)
    {
        // µ¿¿µ»ó »óŸ¦ ¾÷µ¥ÀÌÆ® ½ÃÅ°±â À§ÇØ Timer¸¦ ÀÛµ¿ ½ÃŲ´Ù. 
        OnTimer();

        // µ¿¿µ»ó ½ºÆ®¸®¹Ö ȯ°æÀ» »ý¼º½ÃŲ´Ù.
        OnOpen();
    }

    // ¼³Á¤µÈ ºñµð¿À¸¦ PlayÇÑ´Ù.
    OnPlay();
}

private void pauseButton_Click(object sender, RoutedEventArgs e)
{
{
    // PlayµÇ°í ÀÖ´Â ºñµð¿À¸¦ Pause½ÃŲ´Ù.
    OnPause();
}

private void stopButton_Click(object sender, RoutedEventArgs e)
{
    // Play°¡ Á¾·áµÇ¾úÀ¸¹Ç·Î Timer¸¦ Á¾·á ½ÃŲ´Ù.
    StopTimer();

    // Play¸¦ Áß´ÜÇÑ´Ù.
    OnStop();

    // Play°¡ StopµÇ¾úÀ¸¹Ç·Î SliderÄÁÆ®·Ñ°ú LabelÀ» ÃʱâÈ­ ½ÃŲ´Ù.
    InitSliderLabel();
}

 

1.2.7     InitSliderLabel, OnTimer, StopTimer¸¦ Á¤ÀÇÇÑ´Ù.

private void InitSliderLabel()
{
      // Slider¸¦ ¼³Á¤Çϱâ À§ÇØ ÄÁÆ®·ÑÀÇ ÃÖ´ë°ªÀ» ¼³Á¤ÇÑ´Ù. 
      playControlSlider.Maximum = unchecked((int)VS.totalFrame);

      // Total ½Ã°£¿¡ ´ëÇØ Á¤º¸¸¦ Label·Î ¼³Á¤ÇÑ´Ù. 
      int nTotalSec = unchecked((int)(VS.totalFrame * (1.0 / 30)));
      TimeSpan getTotalTimeSpan = TimeSpan.FromSeconds(nTotalSec);
      string strTime = getTotalTimeSpan.ToString("hh':'mm':'ss");
      totalTimeLabel.Content = strTime;
}

public void OnTimer()
{
    m_timer.Change(0, 100);
}

public void StopTimer()
{
    if (m_timer != null)
    {
        m_timer.Change(System.Threading.Timeout.Infinite, 
System.Threading.Timeout.Infinite);
    }
}

 

1.2.8     Window â¿¡¼­ Video Overlay LayerÄÁÆ®·ÑÀ» Ŭ¸¯ÇÏ°í [¼Ó¼º]-[À̺¥Æ® ] ÅÇ¿¡¼­ OnOrthoRenderÇàÀ» ´õºí Ŭ¸¯ÇÏ¿© nxVideoLayerOverlay1_OnOrthoRenderÇÔ¼ö¸¦ ÀÚµ¿ »ý¼ºÇÑ´Ù. NXVideoDrawArgs ÀÎÀÚ·Î ³Ñ¾î¿À´Â °ªÀ¸·ÎºÎÅÍ PTS°ªÀ» ¾ò¾î ÇöÀç FrameÀÌ ¸î ¹ø°ÀÎÁö¸¦ °è»êÇÏ¿© currentFrame¿¡ ÀúÀåÇϵµ·Ï ÇÑ´Ù. Âü°í·Î OnOrthoRender´Â È­¸éÀÌ °»½ÅµÉ ¶§ ¸¶´Ù È£ÃâµÇ´Â CallbackÇÔ¼öÀÌ´Ù.

// PTS °ªÀ» ¾ò±â À§ÇØ OnOrthoRender ÇÔ¼ö¸¦ ÀÌ¿ëÇÑ´Ù.
private bool nxVideoLayerOverlay1_OnOrthoRender(NXVideoLayer sender, NXVideoDrawArgs DrawArgs)
{

     try
     {
         if (VS.videoChannel == null) return false;

         lock (m_lockCurFrame)
         {
             // ÇöÀç Àç»ýÁßÀÎ È­¸éÀÌ PTS(Presentation TimeStamp) °ª ¾ò¾î¿À±â
             Int64 pts = DrawArgs.PTS;

             // PTS¸¦ ÀÌ¿ëÇÑ ÇöÀç Àç»ýÁßÀÎ È­¸éÀÇ ÇÁ·¹ÀÓ À§Ä¡¸¦ ¾ò¾î¿À±â
             VS.currentFrame = VS.videoChannel.PtsToFrameNumber(pts);
             if (VS.currentFrame >= VS.totalFrame) VS.currentFrame =
 VS.totalFrame;
             if (VS.currentFrame < 0) VS.currentFrame = 0;
          }
       }

         catch (System.Exception ex)
         {
            Console.WriteLine(ex);
         }
       return default(bool);
}

 

1.2.9     TimerÇÔ¼ö¸¦ ÅëÇØ ÇöÀç µµ½ÃµÇ´Â FrameÀÌ ¾î´À Á¤µµ µÇ´Â Áö¿Í °¢Á¾ Àç»ý »óŸ¦ ¾÷µ¥ÀÌÆ® ½ÃÅ°°í ¸¸¾à Play°¡ Á¾·á½ÃÁ¡¿¡ µµ´ÞÇϸé StopÀ» ¼öÇàÇÑ´Ù.

private void timer_Tick(object state)
{
    lock (m_lockCurFrame)
    {
          if (VS.action != VideoAction.STOP)
          {
               // ÇöÀç Àç»ýµÇ°í ÀÖ´Â µ¿¿µ»óÀÇ ½Ã°£À» °è»ê
               int nSec = unchecked((int)(VS.currentFrame * (1.0 / 30)));
               int nTotalSec = unchecked((int)(VS.totalFrame * (1.0 / 30)));

               long nCheckFrame = VS.totalFrame - VS.currentFrame;

               if (nCheckFrame <= 30)
               {
                   nSec = nTotalSec;
               }

               string strTime;

               TimeSpan getTimeSpan = TimeSpan.FromSeconds(nSec);
               strTime = getTimeSpan.ToString("hh':'mm':'ss");
               int nCurFrame = unchecked((int)VS.currentFrame);

               Dispatcher.BeginInvoke(new Action(delegate
               {
                    // ÇöÀç Àç»ýµÇ°í ÀÖ´Â µ¿¿µ»óÀÇ ½Ã°£À» ¹®ÀÚÇüÅ·Πȭ¸é µµ½Ã
                    currentTimeLabel.Content = strTime;

                    // ÇöÀç Àç»ýµÇ°í ÀÖ´Â µ¿¿µ»óÀÇ ½Ã°£À» Track ¹Ù ÄÁÆ®·Ñ¿¡ µµ½Ã
                    playControlSlider.Value = nCurFrame;
                    if (nSec == nTotalSec)
                    {
                        playControlSlider.Value = playControlSlider.Maximum;

                        // Play°¡ Á¾·áµÇ¾úÀ¸¹Ç·Î Timer¸¦ Á¾·á ½ÃŲ´Ù.
                        StopTimer();

                        // Play¸¦ Áß´ÜÇÑ´Ù.
                        OnStop();

                        // Play°¡ StopµÇ¾úÀ¸¹Ç·Î SliderÄÁÆ®·Ñ°ú LabelÀ» ÃʱâÈ­ ½ÃŲ´Ù.
                        InitSliderLabel();
                 }
             }));         
        }
    }
}

 

1.2.10  [F5]Å°¸¦ ´­·¯ ÇÁ·Î±×·¥À» ½ÇÇàÇÏ¿© ȨÆäÀÌÁö¿¡¼­ ´Ù¿î ¹ÞÀº stream.tsÆÄÀÏÀ» OpenÇÑ´Ù.