create/Trim video File using directshow

-2

I need to cut a sequence/period of an avi video file. Let's say the video is 5min long. I need to create a new video for example from time 1min to 2min. only images are mandatory, I don't care about the audio (my videos are without audio)

by using iMediaSeek. GetDuration (out duration) and iMediaSeek. GetAvailable (out earliest, out latest) I have created a sort of a help file (in text format) to get the number of Frames and their duration time. so I know which frame is set at a given time. The problem is, I have no Idea how to extract this frame and make a new avi video file.

There are several examples in the internet how to extract a frame (current Frame) to an image file. but never for a whole sequence and neither a certain Frame at a certain Time. some1 mentioned, I could use IMediaSeeking SetPostion but as far as I found out is that I can "only" set the start position to play the video no more. any help would be great

UPDATE / Solution:

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, and your friend google, it's easy enough to know the basics.

and here is my code:

using 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; }

      // graph builder interfaces
      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"   // AVISource
                                               : "CEA8DEFF-0AF7-4DB9-9A38-FB3C3AEFC0DE"); // osAviSource

         //Graph builder
         pGraphBuilder = new CaptureGraphBuilder2() as ICaptureGraphBuilder2;
         hr = pGraphBuilder.SetFiltergraph(pGraph);
         checkHR(hr, "Can't SetFilterGraph");

         //Add AVI File Source
         IBaseFilter sourceFilter = (IBaseFilter)new AVIDec();
         //sourceFilter.SetSyncSource(null);   //Set Graph Clock to Null
         hr = pGraph.AddFilter(sourceFilter, "AVI File Source");
         checkHR(hr, "Can't add AVI File Source to Graph");
         //set Source filename        
         try
         {
            sourceFilter = DXHelper.CreateFilter(guid);
         }
         catch (System.IO.FileNotFoundException)
         {
            // can try to register and try again
         }
         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");
         }

         //add AVI Mux
         IBaseFilter pAVIMux = (IBaseFilter)new AviDest();
         //pAVIMux.SetSyncSource(null);
         hr = pGraph.AddFilter(pAVIMux, "AVI MUX");
         checkHR(hr, "Can't add AVI Mux to graph");

         //connect AVI File Source and AVI Mux
         hr = pGraph.ConnectDirect(GetPin(sourceFilter, "Video 0"), GetPin(pAVIMux, "Input 01"), null);
         checkHR(hr, "Cant connect AVI File Source to AVI Mux");

         //add File writer
         IBaseFilter pFilewriter = (IBaseFilter)new FileWriter();
         //pFilewriter.SetSyncSource(null);
         hr = pGraph.AddFilter(pFilewriter, "File Writer");
         checkHR(hr, "Can't add File writer to graph");
         //Set destination filename
         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");

         //connect AVI Mux and File writer         
         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();
         //This file registers .dll files as command components in the registry.
         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);

            //Set Start Position
            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);

            //set Stop Position
            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);
         }
      }
   }
}
c#
directshow
asked on Stack Overflow Jan 7, 2019 by Nizar Belhiba • edited Jan 10, 2019 by Nizar Belhiba

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0