using DirectShow; using Sonic; using System; using System.Linq; using System.Windows.Forms; using VideoPlayLib.KnownGuid; namespace VideoPlayLib { public class VideoPlay: IDisposable { //---- fields private readonly Graph _gWrap; private readonly DSFilter _audioRender; private readonly DSPin[] _arrAudioPins; private DSPin _currentAudioOutPin; private VideoInControl[] _vics; //---- ctor public VideoPlay(string mediaFile, params Control[] videoContainers) { _gWrap = new Graph(); _audioRender = new DSFilter(AudioRender.DirectSound); _gWrap.AddFilter(_audioRender, "audio"); var dsfSrc = _gWrap.AddSourceFilter(mediaFile, "src"); if (dsfSrc.Output.Count == 0) { throw new Exception("Not found any output pin from source!"); } if (dsfSrc.Output.Count == 1 && dsfSrc.OutputPin.MediaTypes.Any(p => p.majorType == MediaType.Stream)) { //we got a Stream, should find a spliter var pinSource = dsfSrc.OutputPin; var guid = pinSource.MediaTypes.Where(p => p.subType != Guid.Empty).Select(p => p.subType).FirstOrDefault(); DSFilter dsfSplit; if (guid == MediaSubType.Avi) dsfSplit = new DSFilter(Spliter.Avi); else if (guid == MediaSubTypeGuids.Mp4) dsfSplit = new DSFilter(Spliter.Mp4); else if (guid == MediaSubTypeGuids.Mpg) dsfSplit = new DSFilter(Spliter.Mpeg); else if (guid == MediaSubTypeGuids.Flv) dsfSplit = new DSFilter(Spliter.Flv); else { throw new Exception("Not found any support MediaSubType!"); } _gWrap.AddFilter(dsfSplit, "spliter"); _gWrap.Connect(pinSource, dsfSplit.InputPin); dsfSrc = dsfSplit; } _arrAudioPins = dsfSrc.Output.Where(p => p.MediaTypes.Any(q => q.majorType == MediaType.Audio)).ToArray(); var arrVideoPins = dsfSrc.Output.Where(p => p.MediaTypes.Any(q => q.majorType == MediaType.Video)).ToArray(); if (_arrAudioPins.Any()) { _gWrap.Connect(_currentAudioOutPin = _arrAudioPins.First(), _audioRender.InputPin); } if (!arrVideoPins.Any() || !videoContainers.Any()) return; if (videoContainers.Length == 1) { var videoRender = new DSFilter(VideoRender.MadVr); _gWrap.AddFilter(videoRender, "video"); _gWrap.Connect(arrVideoPins.First(), videoRender.InputPin); _vics = new[] { new VideoInControl(videoRender, videoContainers.First(), false) }; } else //use tee { _vics = new VideoInControl[videoContainers.Length]; //define a tee var dsfInfTee = new DSFilter(Misc.InfTee); _gWrap.AddFilter(dsfInfTee, "infTee"); //connect input pin of tee , from source _gWrap.Connect(arrVideoPins.First(), dsfInfTee.InputPin); //connect output pin of tee , to evety render for (var i = 0; i < videoContainers.Length; i++) { var videoRender = new DSFilter(VideoRender.MadVr); _gWrap.AddFilter(videoRender, "video" + i); //FIXME: 某些情况会出错 TODO: 让tee在解码滤镜之后 _gWrap.Connect(dsfInfTee.Output[i], videoRender.InputPin); _vics[i] = new VideoInControl(videoRender, videoContainers[i], false); } } } //--- members public string[] Audios { get { return _arrAudioPins.Select(p => p.Name).ToArray(); } } public void SetAudio(int index) { var s = _gWrap.GetState(); if (s == FilterState.Running) _gWrap.Stop(); if (_audioRender.InputPin.ConnectedTo.Filter.Value != _currentAudioOutPin.Filter.Value) { _gWrap.RemoveFilter(_audioRender.InputPin.ConnectedTo.Filter); } else { _gWrap.Disconnect(_audioRender.InputPin); _gWrap.Disconnect(_currentAudioOutPin); } _gWrap.Connect(_arrAudioPins[index], _audioRender.InputPin); if (s == FilterState.Running) _gWrap.Run(); _currentAudioOutPin = _arrAudioPins[index]; } public void Play() { _gWrap.Run(); } public void Pause() { _gWrap.Pause(); } public void Dispose() { _gWrap.Abort(); } public double Duration { get { return _gWrap.Duration; } } public double CurrentPosition { get { return _gWrap.CurrentPosition; } set { _gWrap.CurrentPosition = value; } } } }