为啥 DirectShow 加载视频字幕文件?

Posted

技术标签:

【中文标题】为啥 DirectShow 加载视频字幕文件?【英文标题】:Why DirectShow load video subtitle file?为什么 DirectShow 加载视频字幕文件? 【发布时间】:2017-06-30 01:31:20 【问题描述】:

我使用这个类(来自 CodeProject 的found,删除了一些方法和属性以减少代码)通过 DirectShow 播放视频文件,它工作正常。但如果字幕文件存在于文件正在播放的同一文件夹中,则字幕会自动显示。

我想知道哪部分代码与字幕文件有关。如何删除或自定义它?! (如颜色、字体大小、字体名称)

它在 SampleGrabber 过滤器内吗?!

class MediaPlayer : IDisposable

    public enum FileType
    
        Video,
        Audio,
        Invalid
    

    public enum GraphState
    
        Stopped,
        Paused,
        Running,
        Exiting
    

    public IVideoFrameStep frameStep = null;
    public FileType fileType = FileType.Invalid;
    public IGraphBuilder graphBuilder = null;
    public IMediaControl mediaControl = null;
    public IVideoWindow videoWindow = null;
    public IBasicVideo basicVideo = null;
    public ISampleGrabber sampleGrabber = null;
    public IMediaSeeking mediaSeeking = null;
    public IMediaPosition mediaPosition = null;
    public IMediaDet mediaDet = null;
    public IBasicAudio basicAudio = null;
    public IMediaEventEx mediaEvent;
    public Control control;
    public MediaInfo mediaInfo = new MediaInfo();
    public List<Frames> segmentationImages;
    private string filename;
    private ManualResetEvent manualResetEvent = null;
    volatile private GraphState currentState = GraphState.Stopped;
    public event HotMediaEvent StopPlay;

    public void Dispose()
    
        CloseInterfaces();
    

    ~MediaPlayer()
    
        CloseInterfaces();
    

    public MediaPlayer(string fileName)
    
        try
        
            IntPtr eventHandler;
            this.filename = fileName;
            this.SetupInterfaces(fileName);
            DsError.ThrowExceptionForHR(mediaEvent.GetEventHandle(out eventHandler));
            manualResetEvent = new ManualResetEvent(false);
            manualResetEvent.SafeWaitHandle = new Microsoft.Win32.SafeHandles.SafeWaitHandle(eventHandler, true);
            Thread t = new Thread(new ThreadStart(this.EventWait));
            t.Name = "HotMediaEvent Thread";
            t.Start();
        
        catch
        
            Dispose();
            throw;
        
    


    public void SetupInterfaces(string fileName)
    
        this.graphBuilder = (IGraphBuilder)new FilterGraph();
        this.sampleGrabber = (ISampleGrabber)new SampleGrabber();
        ConfigSampleGrabber(this.sampleGrabber);
        this.graphBuilder.AddFilter((IBaseFilter)sampleGrabber, "SampleGrabber");
        DsError.ThrowExceptionForHR(this.graphBuilder.RenderFile(fileName, null));
        this.mediaControl = (IMediaControl)this.graphBuilder;
        this.mediaEvent = (IMediaEventEx)this.graphBuilder;
        this.mediaSeeking = (IMediaSeeking)this.graphBuilder;
        this.mediaPosition = (IMediaPosition)this.graphBuilder;
        this.videoWindow = this.graphBuilder as IVideoWindow;
        this.basicVideo = this.graphBuilder as IBasicVideo;
        this.basicAudio = this.graphBuilder as IBasicAudio;

        this.frameStep = this.graphBuilder as IVideoFrameStep;

        this.mediaDet = (IMediaDet)new MediaDet();
        this.mediaDet.put_Filename(fileName);
        this.CheckFileType();
        if (this.fileType == FileType.Video)
            this.GetMediaInfo();
    


    public void SetupVideoWindow(Control control)
    
        int hr = 0;
        this.control = control;
        if (this.fileType == FileType.Video)
        
            //this.sampleGrabber.SetCallback(((MainForm)this.control.Parent.Parent), 1);
            this.GetMediaInfo();
            hr = this.videoWindow.put_Owner(control.Handle);
            DsError.ThrowExceptionForHR(hr);
            hr = this.videoWindow.put_WindowStyle((WindowStyle.Child | WindowStyle.ClipChildren | WindowStyle.ClipSiblings));
            DsError.ThrowExceptionForHR(hr);
            hr = this.videoWindow.put_Visible(OABool.True);
            DsError.ThrowExceptionForHR(hr);
            hr = this.videoWindow.put_MessageDrain(control.Handle);
            this.SizeWindow();
            DsError.ThrowExceptionForHR(hr);
        
     

    public void ClearVideoWindow()
    
        int hr = 0;
        if (this.fileType == FileType.Video)
        
            hr = this.videoWindow.put_Owner(IntPtr.Zero);
            DsError.ThrowExceptionForHR(hr);
            hr = this.videoWindow.put_Visible(OABool.False);
            DsError.ThrowExceptionForHR(hr);
            hr = this.videoWindow.put_MessageDrain(IntPtr.Zero);
            DsError.ThrowExceptionForHR(hr);
        
    

    private void CheckFileType()
    
        int hr;
        if ((this.videoWindow != null) || (this.basicVideo != null))
            this.fileType = FileType.Video;
        else if ((this.basicAudio != null))
            this.fileType = FileType.Audio;
        else
            this.fileType = FileType.Invalid;

        OABool lVisible;
        hr = this.videoWindow.get_Visible(out lVisible);
        if (hr < 0)
        
            if (hr == unchecked((int)0x80004002)) //E_NOINTERFACE
                this.fileType = FileType.Audio;
            else
                DsError.ThrowExceptionForHR(hr);
        
    

    private void EventWait()
    
        int hr;
        //WS UPDATED changed int to IntPtr
        IntPtr firstParameter, secondParameter;
        EventCode eventCode;
        do
        
            manualResetEvent.WaitOne(-1, true);
            lock (this)
            
                if (currentState != GraphState.Exiting)
                
                    hr = mediaEvent.GetEvent(out eventCode, out firstParameter, out secondParameter, 0);
                    while (hr >= 0)
                    
                        if (eventCode == EventCode.Complete)
                        
                            Stop();
                            if (StopPlay != null)
                                StopPlay(this);
                        
                        hr = mediaEvent.FreeEventParams(eventCode, firstParameter, secondParameter);
                        DsError.ThrowExceptionForHR(hr);
                        hr = mediaEvent.GetEvent(out eventCode, out firstParameter, out secondParameter, 0);
                    
                    if (hr != unchecked((int)0x80004004))
                        DsError.ThrowExceptionForHR(hr);
                
                else
                    break;
            
         while (true);
    

    public void SizeWindow()
    
        int hr;
        Rectangle rc = control.ClientRectangle;
        int windowWidth, windowHeight;
        windowWidth = rc.Width;
        windowHeight = rc.Height;
        int videoWidth = this.mediaInfo.MediaWidth;
        int videoHeight = this.mediaInfo.MediaHeight;
        int x, y, width, height;
        double videoRatio = (double)videoWidth / (double)videoHeight;
        double windowRatio = (double)windowWidth / (double)windowHeight;
        if (videoRatio > windowRatio)
        
            double ratio = (double)windowWidth / (double)videoWidth;
            x = (int)((windowWidth - videoWidth * ratio) / 2);
            y = (int)((windowHeight - videoHeight * ratio) / 2);
            width = (int)(videoWidth * ratio);
            height = (int)(videoHeight * ratio);
            hr = videoWindow.SetWindowPosition(x, y, width, height);
        
        else
        
            double ratio = (double)windowHeight / (double)videoHeight;
            x = (int)((windowWidth - videoWidth * ratio) / 2);
            y = (int)((windowHeight - videoHeight * ratio) / 2);
            width = (int)(videoWidth * ratio);
            height = (int)(videoHeight * ratio);
            hr = videoWindow.SetWindowPosition(x, y, width, height);
        
        DsError.ThrowExceptionForHR(hr);
    

    void ConfigSampleGrabber(ISampleGrabber sampGrabber)
    
        AMMediaType media;
        media = new AMMediaType();
        media.majorType = MediaType.Video;
        media.subType = MediaSubType.RGB24;
        media.formatType = FormatType.VideoInfo;
        this.sampleGrabber.SetMediaType(media);
        DsUtils.FreeAMMediaType(media);
        media = null;
        int hr = sampGrabber.SetBufferSamples(true);
        DsError.ThrowExceptionForHR(hr);
    

    private void GetMediaInfo()
    
        AMMediaType media = new AMMediaType();
        this.sampleGrabber.GetConnectedMediaType(media);
        if ((media.formatType != FormatType.VideoInfo) || (media.formatPtr == IntPtr.Zero))
        
            throw new Exception("Format type incorrect");
        

        int videoWidth, videoHeight, videoStride;
        this.basicVideo.GetVideoSize(out videoWidth, out videoHeight);
        VideoInfoHeader videoInfoHeader = (VideoInfoHeader)Marshal.PtrToStructure(media.formatPtr, typeof(VideoInfoHeader));
        videoStride = videoWidth * (videoInfoHeader.BmiHeader.BitCount / 8);
        this.mediaInfo.MediaWidth = videoWidth;
        this.mediaInfo.MediaHeight = videoHeight;
        this.mediaInfo.MediaStride = videoStride;
        this.mediaInfo.MediaBitCount = videoInfoHeader.BmiHeader.BitCount;
        this.mediaInfo.fps = this.getFramePerSecond();
        this.mediaInfo.duration = this.getDuration();

        this.mediaInfo.sFilePath = this.filename.ToString();

        DsUtils.FreeAMMediaType(media);
        media = null;
    


    private void CloseInterfaces()
    
        lock (this)
        
            int hr;
            try
            
                if (this.mediaControl != null)
                
                    hr = this.mediaControl.StopWhenReady();
                    this.mediaControl = null;
                
                if (currentState != GraphState.Exiting)
                
                    currentState = GraphState.Exiting;
                    if (manualResetEvent != null)
                        manualResetEvent.Set();
                
                if (this.videoWindow != null)
                
                    hr = this.videoWindow.put_Visible(OABool.False);
                    hr = this.videoWindow.put_Owner(IntPtr.Zero);
                    this.videoWindow = null;
                
                this.mediaSeeking = null;
                this.mediaPosition = null;
                this.basicVideo = null;
                this.basicAudio = null;
                this.mediaDet = null;
                if (this.graphBuilder != null)
                    Marshal.ReleaseComObject(this.graphBuilder);
                this.graphBuilder = null;
            
            catch (Exception e)
            
                MessageBox.Show(e.Message);
                return;
            
        
        GC.Collect();
    


    public void Start()
    
        if (this.currentState == GraphState.Stopped || this.currentState == GraphState.Paused)
        
            DsError.ThrowExceptionForHR(mediaControl.Run());
            this.currentState = GraphState.Running;
        
    

    public void Stop()
    
        if (this.currentState == GraphState.Running || this.currentState == GraphState.Paused)
        
            DsError.ThrowExceptionForHR(mediaControl.Stop());
            currentState = GraphState.Stopped;
        
    


    public void End()
    
        double endPosition = 0;
        this.mediaDet.get_StreamLength(out endPosition);
        DsError.ThrowExceptionForHR(mediaPosition.put_CurrentPosition(endPosition));
    


【问题讨论】:

可以给codeproject的链接吗? 【参考方案1】:

很可能是您安装了 DirectVobSub 过滤器(通常作为某些编解码器包的一部分),它以高品质(优先级)注册自己,这允许它在过滤器图构建过程中闯入并将自己插入您的管道甚至不是您代码的一部分。

过滤器会查找字幕文件并自动加载它们,然后更新视频源。

DirectVobSub(以前称为 VSFilter)是 Microsoft Windows 的软件插件(DirectShow 过滤器),能够读取外部字幕文件并将它们叠加在正在播放的视频文件上。

您想卸载它,或禁用它的自动自激活功能。

另见:

Understanding Your DirectShow Filter Graph - 了解哪些过滤器在您的管道中有效

【讨论】:

以上是关于为啥 DirectShow 加载视频字幕文件?的主要内容,如果未能解决你的问题,请参考以下文章

在官方网站下不了迅雷并显示加载DLL失败 程序退出 为啥?

如何把字幕和视频合成到一个文件?

字幕和电影合成

MeGui原滤镜使用心得

如何为 Flash 视频加载字幕文本?

怎么把字幕放到电影里 把字幕嵌入视频