Создание/обрезка видеофайла с помощью directshow
Мне нужно, чтобы сократить последовательность/срок AVI видео файл. Допустим, видео длится 5 минут. Мне нужно создать новое видео, например, от 1 минуты до 2 минут. только изображения обязательны, я не забочусь об аудио (мои видео без звука)
пользуясь
iMediaSeek. GetDuration (out duration) and iMediaSeek. GetAvailable (out earliest, out latest)Я создал своего рода файл справки (в текстовом формате), чтобы получить количество кадров и их продолжительность. поэтому я знаю, какой кадр установлен в данный момент времени. Проблема в том, что я понятия не имею, как извлечь этот кадр и сделать из него новый avi-видеофайл.
**ОБНОВЛЕНИЕ:**
Мне удалось создать график directshow, который считывает видеофайл и делает копию в новый файл. хотя он все еще делает копию исходного файла 1:1, я почти уверен, что смогу справиться с этой задачей с помощью
IMediaSeeking SetPostionкак уже упоминалось ранее.
Чтобы понять процесс работы графа Directshow, я использовал GraphStudioNext.
Как только я закончу, я отправлю окончательный код в качестве ответа.
Что я уже пробовал:
private static void checkHR(int hr, string msg) { if (hr < 0) { LogFileManager.Instance.WriteToLogFile(msg, SwitchLevel.Info); DsError.ThrowExceptionForHR(hr); } } #region Member variables // graph builder interfaces private static ICaptureGraphBuilder2 pGraphBuilder; private static IReferenceClock pClock; #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(); 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(); 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; } public static void createNewFile(string fileName, string newFile) { try { IGraphBuilder graph = (IGraphBuilder)new FilterGraph(); LogFileManager.Instance.WriteToLogFile("Building graph...", SwitchLevel.Info); BuildGraph(graph, fileName, "D:\\Test_Cut2.avi"); LogFileManager.Instance.WriteToLogFile("Running...", SwitchLevel.Info); IMediaControl mediaControl = (IMediaControl)graph; IMediaEvent mediaEvent = (IMediaEvent)graph; 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); } } }