And here we go, for those who need to do something similar It's not that difficult as I thought in the beginning, when you know what you have to do! And that was exactly my main issue. I had no idea what to do or how to approach the task. So to get started in DirectShow you need to build a graph which do for you the task. I recommend to use GraphEdit provided with the SDK, or in my case GraphStudioNext. the best way to start is if you have any program that play's a video file or better an application that make a video file from a web cam. with the editor you can connect to that application and it will generate for you the graph used. Then you can create/simulate your own graph with your needs.
After that you only need to code your own graph. With the help of the documentations, the c++ code from the link provided by @RickZeeland in answer1 and your friend google, it's easy enough to know the basics.
and here is my code:
sing System;
using System.Collections.Generic;
using System.Runtime.InteropServices.ComTypes;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
using DirectShowLib;
namespace Modules.File.Video
{
public class AviSplitter
{
private static void checkHR(int hr, string msg)
{
if (hr < 0)
{
LogFileManager.Instance.WriteToLogFile(msg, SwitchLevel.Info);
DsError.ThrowExceptionForHR(hr);
}
}
#region Member variables
public static double Duration { get; private set; }
public static long NrFramesInAVI { get; private set; }
private static ICaptureGraphBuilder2 pGraphBuilder;
private static IMediaSeeking pmediaSeeking;
#endregion
private static void BuildGraph(IGraphBuilder pGraph, string FileName, string NewFile)
{
const bool USEDAVISPLITTER = false;
int hr = 0;
Guid guid = new Guid(USEDAVISPLITTER ? "D3588AB0-0781-11CE-B03A-0020AF0BA770"
: "CEA8DEFF-0AF7-4DB9-9A38-FB3C3AEFC0DE");
pGraphBuilder = new CaptureGraphBuilder2() as ICaptureGraphBuilder2;
hr = pGraphBuilder.SetFiltergraph(pGraph);
checkHR(hr, "Can't SetFilterGraph");
IBaseFilter sourceFilter = (IBaseFilter)new AVIDec();
hr = pGraph.AddFilter(sourceFilter, "AVI File Source");
checkHR(hr, "Can't add AVI File Source to Graph");
try
{
sourceFilter = DXHelper.CreateFilter(guid);
}
catch (System.IO.FileNotFoundException)
{
}
if (null == sourceFilter) sourceFilter = RegisterAviSplitter(guid);
if (null != sourceFilter)
{
DsError.ThrowExceptionForHR(pGraph.AddFilter(sourceFilter, "sourceFilter"));
IFileSourceFilter sourceFilter_src = sourceFilter as IFileSourceFilter;
if (sourceFilter_src == null) checkHR(unchecked((int)0x80004002), "Cant't get IFileSourceFilter");
hr = sourceFilter_src.Load(FileName, null);
checkHR(hr, "Can't load file");
}
IBaseFilter pAVIMux = (IBaseFilter)new AviDest();
hr = pGraph.AddFilter(pAVIMux, "AVI MUX");
checkHR(hr, "Can't add AVI Mux to graph");
hr = pGraph.ConnectDirect(GetPin(sourceFilter, "Video 0"), GetPin(pAVIMux, "Input 01"), null);
checkHR(hr, "Cant connect AVI File Source to AVI Mux");
IBaseFilter pFilewriter = (IBaseFilter)new FileWriter();
hr = pGraph.AddFilter(pFilewriter, "File Writer");
checkHR(hr, "Can't add File writer to graph");
IFileSinkFilter pFilewriter_sink = pFilewriter as IFileSinkFilter;
if (pFilewriter_sink == null) checkHR(unchecked((int)0x8004002), "Can't get IFileSinkFilter");
hr = pFilewriter_sink.SetFileName(NewFile, null);
checkHR(hr, "Can't set filename");
hr = pGraph.ConnectDirect(GetPin(pAVIMux, "AVI Out"), GetPin(pFilewriter, "in"), null);
checkHR(hr, "Can't connect AVI Mux and File writer");
}
private static IBaseFilter RegisterAviSplitter(Guid guid)
{
string filePath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\registerOSAviSplitter.bat";
System.Diagnostics.Process reg = new System.Diagnostics.Process();
reg.StartInfo.FileName = filePath;
reg.StartInfo.UseShellExecute = false;
reg.StartInfo.CreateNoWindow = true;
reg.StartInfo.RedirectStandardOutput = true;
reg.Start();
reg.WaitForExit(10 * 1000);
reg.Close();
System.Threading.Thread.Sleep(2000);
return DXHelper.CreateFilterSafe(guid);
}
private static IPin GetPin(IBaseFilter filter, string pinname)
{
IEnumPins epins;
int hr = filter.EnumPins(out epins);
checkHR(hr, "Can't ennumerate pins");
IntPtr fetched = Marshal.AllocCoTaskMem(4);
IPin[] pins = new IPin[1];
while (epins.Next(1, pins, fetched) == 0)
{
PinInfo pinfo;
pins[0].QueryPinInfo(out pinfo);
bool found = (pinfo.name == pinname);
DsUtils.FreePinInfo(pinfo);
if (found) return pins[0];
}
checkHR(-1, "Pin not found");
return null;
}
private static double TimeOfFrame(long frame)
{
double time = (double)frame * Duration;
return time / (double)NrFramesInAVI;
}
private static double TimeOfMediaTime(long mediaTime)
{
return ((double)mediaTime / 10000000.0);
}
private static long MediaTimeOfTime(double time)
{
return (long)(time * 10000000.0);
}
private static double getDuration()
{
if (pmediaSeeking == null) return 0.1;
long duration; pmediaSeeking.GetDuration(out duration);
return TimeOfMediaTime(duration);
}
private static long GetNbOfFrames()
{
long ret = 0;
if (pmediaSeeking != null)
{
try
{
long earliest, latest;
pmediaSeeking.SetTimeFormat(TimeFormat.Frame);
pmediaSeeking.GetAvailable(out earliest, out latest);
pmediaSeeking.SetTimeFormat(TimeFormat.MediaTime);
return latest;
}
catch { }
}
return ret;
}
public static void createNewFile(string fileName, string newFile, long startPos, long endPos)
{
try
{
IGraphBuilder graph = (IGraphBuilder)new FilterGraph();
LogFileManager.Instance.WriteToLogFile("Building graph...", SwitchLevel.Info);
BuildGraph(graph, fileName, "D:\\Test_Cut3.avi");
LogFileManager.Instance.WriteToLogFile("Running...", SwitchLevel.Info);
IMediaControl mediaControl = (IMediaControl)graph;
IMediaEvent mediaEvent = (IMediaEvent)graph;
pmediaSeeking = (IMediaSeeking)graph;
NrFramesInAVI = GetNbOfFrames();
Duration = getDuration();
pmediaSeeking?.SetTimeFormat(TimeFormat.MediaTime);
long Starttime = MediaTimeOfTime(TimeOfFrame(startPos));
LogFileManager.Instance.WriteToLogFile("Set Start at frame: " + startPos.ToString() + "[" + (Starttime / 10000000).ToString() + "])", SwitchLevel.Info);
pmediaSeeking.SetPositions(Starttime, AMSeekingSeekingFlags.AbsolutePositioning, 0, AMSeekingSeekingFlags.NoPositioning);
long endtime = MediaTimeOfTime(TimeOfFrame(endPos));
LogFileManager.Instance.WriteToLogFile("Set End at frame: " + endPos.ToString() + "[" + (Starttime / 10000000).ToString() + "])", SwitchLevel.Info);
pmediaSeeking.SetPositions(endtime, AMSeekingSeekingFlags.NoPositioning, 0, AMSeekingSeekingFlags.AbsolutePositioning);
int hr = mediaControl.Run();
checkHR(hr, "Can't run the graph");
bool stop = false;
while (!stop)
{
Thread.Sleep(500);
LogFileManager.Instance.WriteToLogFile(".", SwitchLevel.Info);
EventCode ev;
IntPtr p1, p2;
Application.DoEvents();
while (mediaEvent.GetEvent(out ev, out p1, out p2, 0) == 0)
{
if (ev == EventCode.Complete || ev == EventCode.UserAbort)
{
mediaControl.StopWhenReady();
LogFileManager.Instance.WriteToLogFile("Done!", SwitchLevel.Info);
stop = true;
}
else if (ev == EventCode.ErrorAbort)
{
LogFileManager.Instance.WriteToLogFile(string.Format("An error occured: HRESULT={0,X}", p1), SwitchLevel.Info);
mediaControl.Stop();
stop = true;
}
mediaEvent.FreeEventParams(ev, p1, p2);
}
}
}
catch (COMException ex)
{
ErrorManager.Instance.HandleException(ex, SwitchLevel.Error);
LogFileManager.Instance.WriteToLogFile("COM error: " + ex.ToString(), SwitchLevel.Info);
}
catch (Exception ex)
{
LogFileManager.Instance.WriteToLogFile("Error: " + ex.ToString(), SwitchLevel.Info);
ErrorManager.Instance.HandleException(ex, SwitchLevel.Error);
}
}
}
}