using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using DirectShowLib;
namespace CsVidSeg
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.TrackBar trackBar1;
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.Button buttonPlay;
private System.Windows.Forms.Button buttonPause;
private System.Windows.Forms.Button buttonStop;
private System.Windows.Forms.Button buttonFramestep;
private System.Windows.Forms.Button buttonLoop;
// some variables
bool bLoop = false;
bool canStep = false;
int minutes, seconds;
string fileName;
// filter graph and different interfaces
FilterGraph fg = null;
IGraphBuilder graphBuilder = null;
IMediaControl mediaCtrl = null;
IMediaEventEx mediaEvt = null;
IMediaPosition mediaPos = null;
IVideoFrameStep frameStep = null;
IVideoWindow videoWin = null;
IVideoWindow videoWin2 = null;
// We'll use an Infinite Tee filter object to duplicate the
// video stream by two
InfTee tee = null;
// We'll only treat wmv format
WMAsfReader reader = null;
// The Sobel object and filter interface
object sobelObject = null;
IBaseFilter sobel = null;
// the black and white filter interface
IBaseFilter bw = null;
// the Guids for our custom filters
Guid sobelGuid = new Guid( "1C826B9A-4008-4C41-B601-A783A40AFAB2" );
Guid bwGuid = new Guid( "0C017086-684E-41c9-A4BB-640570C64B28" );
// Some states variables, I could have used DSLib ones instead
enum State { Playing, Paused, Stopped };
State graphState;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.StatusBarPanel statusBarPanel1;
private System.Windows.Forms.StatusBar statusBar1;
private System.Windows.Forms.Panel panel2;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Button buttonOpen;
private System.ComponentModel.IContainer components;
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
trackBar1.Minimum = 0;
trackBar1.Maximum = 256;
trackBar1.Enabled = true;
trackBar1.Value = 128;
statusBar1.Panels[0].Text = "Duration: 00m:00s";
fileName = "";
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.label2 = new System.Windows.Forms.Label();
this.label1 = new System.Windows.Forms.Label();
this.trackBar1 = new System.Windows.Forms.TrackBar();
this.buttonLoop = new System.Windows.Forms.Button();
this.buttonFramestep = new System.Windows.Forms.Button();
this.buttonStop = new System.Windows.Forms.Button();
this.buttonPause = new System.Windows.Forms.Button();
this.buttonPlay = new System.Windows.Forms.Button();
this.panel1 = new System.Windows.Forms.Panel();
this.statusBarPanel1 = new System.Windows.Forms.StatusBarPanel();
this.statusBar1 = new System.Windows.Forms.StatusBar();
this.panel2 = new System.Windows.Forms.Panel();
this.buttonOpen = new System.Windows.Forms.Button();
this.groupBox1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.trackBar1)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.statusBarPanel1)).BeginInit();
this.SuspendLayout();
//
// groupBox1
//
this.groupBox1.Controls.AddRange(new System.Windows.Forms.Control[] {
this.buttonOpen,
this.label2,
this.label1,
this.trackBar1,
this.buttonLoop,
this.buttonFramestep,
this.buttonStop,
this.buttonPause,
this.buttonPlay});
this.groupBox1.Location = new System.Drawing.Point(8, 0);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(664, 88);
this.groupBox1.TabIndex = 9;
this.groupBox1.TabStop = false;
//
// label2
//
this.label2.Location = new System.Drawing.Point(256, 56);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(88, 24);
this.label2.TabIndex = 8;
this.label2.Text = "Threshold";
//
// label1
//
this.label1.Location = new System.Drawing.Point(24, 56);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(136, 23);
this.label1.TabIndex = 7;
this.label1.Text = "Treshold value: 128";
//
// trackBar1
//
this.trackBar1.AutoSize = false;
this.trackBar1.Location = new System.Drawing.Point(344, 40);
this.trackBar1.Name = "trackBar1";
this.trackBar1.Size = new System.Drawing.Size(312, 45);
this.trackBar1.TabIndex = 6;
this.trackBar1.TickStyle = System.Windows.Forms.TickStyle.TopLeft;
this.trackBar1.ValueChanged += new System.EventHandler(this.trackBar1_ValueChanged);
//
// buttonLoop
//
this.buttonLoop.Location = new System.Drawing.Point(560, 16);
this.buttonLoop.Name = "buttonLoop";
this.buttonLoop.Size = new System.Drawing.Size(88, 24);
this.buttonLoop.TabIndex = 5;
this.buttonLoop.Text = "Loop";
this.buttonLoop.Click += new System.EventHandler(this.buttonLoop_Click);
//
// buttonFramestep
//
this.buttonFramestep.Enabled = false;
this.buttonFramestep.Location = new System.Drawing.Point(448, 16);
this.buttonFramestep.Name = "buttonFramestep";
this.buttonFramestep.Size = new System.Drawing.Size(88, 24);
this.buttonFramestep.TabIndex = 3;
this.buttonFramestep.Text = "Framestep";
this.buttonFramestep.Click += new System.EventHandler(this.buttonFramestep_Click);
//
// buttonStop
//
this.buttonStop.Location = new System.Drawing.Point(344, 16);
this.buttonStop.Name = "buttonStop";
this.buttonStop.Size = new System.Drawing.Size(88, 24);
this.buttonStop.TabIndex = 2;
this.buttonStop.Text = "Stop";
this.buttonStop.Click += new System.EventHandler(this.buttonStop_Click);
//
// buttonPause
//
this.buttonPause.Location = new System.Drawing.Point(232, 16);
this.buttonPause.Name = "buttonPause";
this.buttonPause.Size = new System.Drawing.Size(88, 24);
this.buttonPause.TabIndex = 1;
this.buttonPause.Text = "Pause";
this.buttonPause.Click += new System.EventHandler(this.buttonPause_Click);
//
// buttonPlay
//
this.buttonPlay.Location = new System.Drawing.Point(120, 16);
this.buttonPlay.Name = "buttonPlay";
this.buttonPlay.Size = new System.Drawing.Size(88, 24);
this.buttonPlay.TabIndex = 0;
this.buttonPlay.Text = "Play";
this.buttonPlay.Click += new System.EventHandler(this.buttonPlay_Click);
//
// panel1
//
this.panel1.Location = new System.Drawing.Point(8, 104);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(320, 240);
this.panel1.TabIndex = 4;
//
// statusBarPanel1
//
this.statusBarPanel1.Alignment = System.Windows.Forms.HorizontalAlignment.Center;
this.statusBarPanel1.AutoSize = System.Windows.Forms.StatusBarPanelAutoSize.Contents;
this.statusBarPanel1.Width = 10;
//
// statusBar1
//
this.statusBar1.Location = new System.Drawing.Point(0, 360);
this.statusBar1.Name = "statusBar1";
this.statusBar1.Panels.AddRange(new System.Windows.Forms.StatusBarPanel[] {
this.statusBarPanel1});
this.statusBar1.ShowPanels = true;
this.statusBar1.Size = new System.Drawing.Size(680, 22);
this.statusBar1.SizingGrip = false;
this.statusBar1.TabIndex = 6;
//
// panel2
//
this.panel2.Location = new System.Drawing.Point(352, 104);
this.panel2.Name = "panel2";
this.panel2.Size = new System.Drawing.Size(320, 240);
this.panel2.TabIndex = 7;
//
// buttonOpen
//
this.buttonOpen.Location = new System.Drawing.Point(16, 16);
this.buttonOpen.Name = "buttonOpen";
this.buttonOpen.Size = new System.Drawing.Size(88, 24);
this.buttonOpen.TabIndex = 0;
this.buttonOpen.Text = "Open";
this.buttonOpen.Click += new System.EventHandler(this.buttonOpen_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(680, 382);
this.Controls.AddRange(new System.Windows.Forms.Control[] {
this.panel2,
this.statusBar1,
this.panel1,
this.groupBox1});
this.MaximizeBox = false;
this.Name = "Form1";
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
this.Text = "Video Segmentation in C#";
this.groupBox1.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.trackBar1)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.statusBarPanel1)).EndInit();
this.ResumeLayout(false);
}
#endregion
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
//
//This method create the filter graph
//
void InitInterfaces()
{
try
{
fg = new FilterGraph();
graphBuilder = (IGraphBuilder) fg;
mediaCtrl = (IMediaControl) fg;
mediaEvt = (IMediaEventEx) fg;
mediaPos = (IMediaPosition) fg;
}
catch(Exception)
{
MessageBox.Show( "Couldn't start" );
}
}
//
//This method stop the filter graph and ensures that we stop
//sending messages to our window
//
void CloseInterfaces()
{
if( mediaCtrl != null )
{
mediaCtrl.StopWhenReady();
mediaEvt.SetNotifyWindow( (IntPtr)0, WM_GRAPHNOTIFY, (IntPtr)0 );
}
mediaCtrl = null;
mediaEvt = null;
mediaPos = null;
if( canStep )
frameStep = null;
videoWin = null;
videoWin2 = null;
if( fg != null )
Marshal.ReleaseComObject(this.fg);
fg = null;
}
//
// This method checks if a pin is processing a video stream
//
bool CheckVideo( IPin pin )
{
AMMediaType mt = new AMMediaType();
mt.majorType = MediaType.Video;
if( pin.QueryAccept( mt ) == 0 )
return true;
else
return false;
}
//
// This method find the second renderer in the filter graph;
// it assumes that the first renderer had its "owner" property set
//
IVideoWindow GetSecondRenderer()
{
IEnumFilters enumFilters;
ArrayList filtersArray = new ArrayList();
IFilterGraph filterGraph = (IFilterGraph)fg;
filterGraph.EnumFilters(out enumFilters);
IBaseFilter[] filters = new IBaseFilter[1];
int fetched;
while(enumFilters.Next(1, filters, out fetched) == 0)
{
IVideoWindow ivw = filters[0] as IVideoWindow;
if( ivw != null )
{
IntPtr outPtr = new IntPtr();
ivw.get_Owner( out outPtr );
if( outPtr == IntPtr.Zero )
return ivw;
}
}
return null;
}
//
//Method to start to play a media file
//
void LoadFile( string fName )
{
try
{
// build the graph
// create sobel filter
Type t = Type.GetTypeFromCLSID( sobelGuid );
sobelObject = Activator.CreateInstance( t );
sobel = (IBaseFilter)sobelObject;
// create the black and white filter
t = Type.GetTypeFromCLSID( bwGuid );
bw = (IBaseFilter)Activator.CreateInstance( t );
// create the infinite tee filter
tee = new InfTee();
// add all these filters to the graph
graphBuilder.AddFilter( sobel, "Sobel" );
graphBuilder.AddFilter( bw, "BW" );
graphBuilder.AddFilter( (IBaseFilter)tee, "Tee" );
// prepare our asf reader object
reader = new WMAsfReader();
((IFileSourceFilter)reader).Load( fName, null );
graphBuilder.AddFilter( (IBaseFilter)reader, "Reader" );
// connect video source to infinite tee filter
IPin teeInput = DsFindPin.ByDirection( (IBaseFilter)tee, PinDirection.Input, 0 );
IPin vidOutput = DsFindPin.ByDirection( (IBaseFilter)reader, PinDirection.Output, 0 );
// check if the video stream is on the first pin
if( CheckVideo( vidOutput ) )
graphBuilder.Connect( vidOutput, teeInput );
else // video stream is on second pin
{
vidOutput = DsFindPin.ByDirection( (IBaseFilter)reader, PinDirection.Output, 1 );
graphBuilder.Connect( vidOutput, teeInput );
}
// render output pin of tee
IPin teeOutput = DsFindPin.ByDirection( (IBaseFilter)tee, PinDirection.Output, 0 );
graphBuilder.Render( teeOutput );
//check for the ability to step
frameStep = fg as IVideoFrameStep;
if( frameStep.CanStep( 1, null ) == 0 )
{
canStep = true;
buttonFramestep.Enabled = true;
}
//prepare and set the first video window
videoWin = fg as IVideoWindow;
videoWin.put_Owner( (IntPtr)panel2.Handle );
videoWin.put_WindowStyle( WindowStyle.Child | WindowStyle.ClipSiblings | WindowStyle.ClipChildren );
Rectangle rc = panel2.ClientRectangle;
videoWin.SetWindowPosition( 0, 0, rc.Right, rc.Bottom );
mediaEvt.SetNotifyWindow( (IntPtr)this.Handle, WM_GRAPHNOTIFY, (IntPtr)0 );
// render original video from second output pin
IPin teeOutput2 = DsFindPin.ByDirection( (IBaseFilter)tee, PinDirection.Output, 1 );
graphBuilder.Render( teeOutput2 );
// setup second video window
videoWin2 = GetSecondRenderer();
if( videoWin2 != null )
{
videoWin2.put_Owner( (IntPtr)panel1.Handle );
videoWin2.put_WindowStyle( WindowStyle.Child | WindowStyle.ClipSiblings | WindowStyle.ClipChildren );
rc = panel1.ClientRectangle;
videoWin2.SetWindowPosition( 0, 0, rc.Right, rc.Bottom );
}
//set the different values for controls
Text = fName;
double duration;
mediaPos.get_Duration( out duration);
trackBar1.Value = 128;
minutes = (int)duration/60;
seconds = (int)duration % 60;
statusBar1.Panels[0].Text = "Duration: " + minutes.ToString( "D2" )
+ ":m" + seconds.ToString( "D2" ) + ":s" ;
graphState = State.Playing;
//DsROTEntry rot = new DsROTEntry( (IFilterGraph)fg );
//start the playback
mediaCtrl.Run();
}
catch( Exception ) { Text = "Error loading file"; }
}
//different constant needed by the app
const int WM_GRAPHNOTIFY = 0x00008001;
const int WS_CHILD = 0x40000000;
const int WS_CLIPCHILDREN = 0x02000000;
const int WS_CLIPSIBLINGS = 0x04000000;
const int WM_MOVE = 0x00000003;
const int EC_COMPLETE = 0x00000001;
//
//override to process custom graph notify messages
//
protected override void WndProc( ref Message m )
{
if( m.Msg == WM_GRAPHNOTIFY )
{
if( mediaEvt != null )
OnGraphNotify();
return;
}
base.WndProc( ref m );
}
//
//call to process WM_GRAPHNOTIFY message
//get out of the loop when GetEvent returns not 0
//
void OnGraphNotify()
{
int p1, p2;
EventCode code;
if( mediaEvt == null )
return;
while( mediaEvt.GetEvent( out code, out p1, out p2, 0 ) == 0 )
{
mediaEvt.FreeEventParams( code, p1, p2 );
if( code == EventCode.Complete )
OnClipCompleted();
}
}
//
//method that update the graph filter and/or gui controls
//when we have received a message that the media file is done playing
//
void OnClipCompleted()
{
graphState = State.Stopped;
if( mediaCtrl == null )
return;
mediaCtrl.Stop();
if( bLoop )
{
mediaPos.put_CurrentPosition( 0.0 );
mediaCtrl.Run();
}
}
//
// Display a dialog box to have the user chose a video file
//
private void buttonOpen_Click(object sender, System.EventArgs e)
{
// if the graph is not stopped, stop it now
if( mediaCtrl != null && graphState != State.Stopped )
{
mediaCtrl.Stop();
graphState = State.Stopped;
}
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "WMVideo (*.wmv)|*.wmv";
if( ofd.ShowDialog() == DialogResult.OK )
{
CloseInterfaces();
InitInterfaces();
fileName = ofd.FileName;
LoadFile( fileName );
}
}
//
// if user clicks play then play video file or restart if stopped
//
private void buttonPlay_Click(object sender, System.EventArgs e)
{
if( mediaCtrl != null && graphState == State.Paused )
{
mediaCtrl.Run();
graphState = State.Playing;
}
if( mediaCtrl != null && graphState == State.Stopped )
{
mediaCtrl.Stop();
mediaPos.put_CurrentPosition( 0.0 );
mediaCtrl.Run();
}
}
//
// pause button handler
//
private void buttonPause_Click(object sender, System.EventArgs e)
{
if( mediaCtrl != null && graphState != State.Paused )
{
mediaCtrl.Pause();
graphState = State.Paused;
}
}
//
// stop button handler
//
private void buttonStop_Click(object sender, System.EventArgs e)
{
if( mediaCtrl != null && graphState != State.Stopped )
{
mediaCtrl.Stop();
graphState = State.Stopped;
}
}
//
//when the user grabs the trackbar, we change the Sobel
//treshold value and step one frame (if possible) or run again
//
private void trackBar1_ValueChanged(object sender, System.EventArgs e)
{
if( mediaCtrl != null )
{
mediaCtrl.Pause();
// access the ISobel interface on the sobel object
ISobel isobel = sobelObject as ISobel;
if( isobel != null )
{
isobel.SetThreshold( trackBar1.Value );
label1.Text = "Treshold value: " + trackBar1.Value.ToString();
}
if( frameStep != null )
{
frameStep.Step( 1, null );
graphState = State.Paused;
}
else
mediaCtrl.Run();
}
}
//
// loop button handler
private void buttonLoop_Click(object sender, System.EventArgs e)
{
bLoop = ! bLoop;
}
//
// frame stepping handler
//
private void buttonFramestep_Click(object sender, System.EventArgs e)
{
if( frameStep != null )
{
mediaCtrl.Pause();
graphState = State.Paused;
frameStep.Step( 1, null );
}
}
}
//
// The ISobel interface is a custom COM interface
// exposed by the Sobel filter, in order to access it
// from C#, we need to define it
//
[Guid("263AFD9E-465C-4dde-9BB1-168C25E2B87F"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ISobel
{
int SetThreshold( int newValue );
}
}