piXoneer Development Library
XDL 3.0 for C#
NXVideoView를 활용하여 동영상 플레이어를 구현해 봅니다.
여기에서는 Timer를 통해 총 Frame수와 현재 도시되는 Frame정보를 획득하여 TrackBar를 통해 정보를 업데이트하여 도시하게 됩니다
C#
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 객체
C#
public Form1()
{
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;
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
// Play가 종료되었으므로 Timer를 종료한다.
StopTimer();
// Play를 중단한다.
OnStop();
if (m_videoIO != null)
{
// 동영상 입출력 객체 Dispose
m_videoIO.Dispose();
}
}
C#
// 동영상 파일 열기
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();
// 동영상의 Frame 정보를 얻어오기
VS.totalFrame = VS.videoChannel.GetNumFramesVideo();
}
catch (Exception ex)
{
Console.WriteLine(ex);
MessageBox.Show(this, "재생 실패!", "동영상");
VS.action = VideoAction.STOP;
}
}
C#
// 동영상 정지버튼클릭 이벤트
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;
}
C#
private void toolStripMenuOpen_Click(object sender, EventArgs e)
{
// 새로운 파일 Open을 수행한다.
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "TS file(*.ts)|*.ts||";
openFileDialog.RestoreDirectory = true;
if (openFileDialog.ShowDialog() != DialogResult.OK) return;
string videoPath = openFileDialog.FileName;
// 동영상 파일의 존재 유무 체크
if (System.IO.File.Exists(videoPath) == false)
{
MessageBox.Show(this, "해당 경로에 영상이 없습니다.", "오류");
return;
}
// 파일 경로를 저장한다.
VS.videoFilePath = videoPath;
// 둥영상의 재생상태가 중지가 아닐 경우 동영상 재생 중지
OnStop();
// 동영상 스트리밍 환경을 생성한다.=.
OnOpen();
// 동영상 상태를 업데이트하기 위해 Timer를 작동한다. 100msec간격으로 설정한다.
OnTimer();
// Play되는 시간 정보를 도시하기 위해 Timer설정과 TrackBar와 Label을 초기화 한다.
InitTrackBarLabel();
// 동영상을 Play한다.
OnPlay();
}
C#
private void button_Play_Click(object sender, EventArgs e)
{
// 비디오가 Stop인 상태인 경우 다시 비디오를 저장된 파일 경로로부터 Open해서 설정한다.
if (VS.action == VideoAction.STOP)
{
// 동영상 상태를 업데이트하기 위해 Timer를 작동한다.
OnTimer();
// 동영상 스트리밍 환경을 생성한다.
OnOpen();
}
// 설정된 비디오를 Play한다.
OnPlay();
}
private void button_Pause_Click(object sender, EventArgs e)
{
// Play되고 있는 비디오를 Pause한다.
OnPause();
}
private void button_Stop_Click(object sender, EventArgs e)
{
// Play가 종료되었으므로 Timer를 종료한다.
StopTimer();
// Play를 중단한다.
OnStop();
// Play가 Stop되었으므로 TrackBar컨트롤과 Label을 초기화한다.
InitTrackBarLabel();
}
C#
public void InitTrackBarLabel()
{
// TrackBar를 설정하기 위해 컨트롤의 최대값을 설정한다.
trackBar_PlayControl.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");
label_TotalTime.Text = 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);
}
}
C#
// 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);
}
C#
// 재생 상태 처리를 위한 타이머 함수
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);
BeginInvoke(new Action(delegate
{
// 현재 재생되고 있는 동영상의 시간을 문자형태로 화면 도시
label_CurrentTime.Text = strTime;
// 현재 재생되고 있는 동영상의 시간을 Track 바 컨트롤에 도시
trackBar_PlayControl.Value = nCurFrame;
if (nSec == nTotalSec)
{
// Play가 종료되었으므로 Timer를 종료한다.
StopTimer();
// Play를 중단한다.
OnStop();
// Play가 Stop되었으므로 TrackBar컨트롤과 Label을 초기화한다.
InitTrackBarLabel();
}
}));
}
}
}
Number | Control Type | Name |
---|---|---|
(1)) | Label | currentTimeLabel |
(2) | Slider | playControlSlider |
(3) | Label | totalTimeLabl |
C#
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 객체
C#
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.action = VideoAction.STOP;
VS.totalFrame = 0;
VS.currentFrame = 0;
}
C#
// 동영상 파일 열기
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();
// 동영상의 Frame 정보를 얻어오기
VS.totalFrame = VS.videoChannel.GetNumFramesVideo();
}
catch (Exception ex)
{
Console.WriteLine(ex);
MessageBox.Show(this, "재생 실패!", "동영상");
VS.action = VideoAction.STOP;
}
}
C#
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;
}
C#
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();
// 동영상 스트리밍 환경을 생성한다.
OnOpen();
// Play되는 시간 정보를 도시하기 위해 Timer설정과 Slider와 Label을 초기화 한다.
InitSliderLabel();
// 동영상을 Play한다.
OnPlay();
}
C#
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();
}
C#
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);
}
}
C#
// 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);
}
C#
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();
}
}));
}
}
}