none
请教 关于C#同步播放视频的问题 RRS feed

  • 问题

  • 问题是这样的,我的程序有两个子窗体,子窗体中使用windows media player 控件播放视频.我需要两个窗体同时播放同一段视频,并且保持视频播放同步,意思是任何时间看两个屏幕中的内容都是一样的,能做到吗?各位大哥给我想想办法吧.
    2010年7月19日 5:02

答案

  • 他的具体需求是什么?如果是类似“画中画”的功能 (也就是多个区域显示同一图像或视频),您又在使用 Windows 7,则可以用 Thumbnail and Preview API 实现 (类似于任务栏上的小 Media Player 窗口,与大的窗口的播放是完全同步的),如果是其他操作系统的话。。。有点困难,如果需要显示的区域位于同一个显示器上,那么,原理是利用 DirectX SDK 抓取 Windows Media Player 的 DX 区域,并每隔一段时间 (如 1/24s) 拷贝一次到指定区域,这里不能用 PrintWindow 函数,因为 PrintWindow 抓不到 DirectShow 图像。

    关于 Windows 7 缩略图和预览 API 的例子,参见 Microsoft All-in-One Code Framework。

    其他参考:

    http://blogs.microsoft.co.il/blogs/sasha/archive/2009/08/12/windows-7-taskbar-tabbed-thumbnails-and-previews-in-native-code.aspx
    http://blogs.microsoft.co.il/blogs/sasha/archive/2009/03/06/windows-7-taskbar-thumbnail-clip-and-custom-previews.aspx


    Mark Zhou
    2010年7月19日 8:17
  • Form1:
            private void Form1_Load(object sender, EventArgs e)
            {
                Form2 Form21 = new Form2();
                Form21.IsBase = true;
                Form21.Show();
                Form21.Text = "主";
                Form2 Form22 = new Form2();
                Form22.IsBase = false;
                Form22.Show();
                Form22.Text = "从";
                Form21.play(@"d:\clock.avi");
                Thread.Sleep(1500);
                Form22.play(@"d:\clock.avi");

    Form2:
        public partial class Form2 : Form
        {
            public Form2()
            {
                InitializeComponent();
            }
            public bool IsBase = true; // true表示以此窗体为基准。
            public static double basePosition = 0;
            private void Form2_Load(object sender, EventArgs e)
            {
                this.axWindowsMediaPlayer1.settings.setMode("loop", true);
            }
            public void play(string URL)
            {
                this.axWindowsMediaPlayer1.URL = URL;
                timer1.Enabled = true;
            }
            private void timer1_Tick(object sender, EventArgs e) // 10毫秒触发一次,或者更短。
            {
                if (this.IsBase)
                {
                    basePosition = this.axWindowsMediaPlayer1.Ctlcontrols.currentPosition;
                }
                else
                {
                    double temp = System.Math.Abs(this.axWindowsMediaPlayer1.Ctlcontrols.currentPosition - basePosition);
                    if (temp > 0.05) // 没具体研究过,听说每秒24帧,1/24=0.04167。
                    {
                        this.axWindowsMediaPlayer1.Ctlcontrols.currentPosition = basePosition;
                    }
                }
            }
        }

    2010年7月20日 7:13

全部回复

  • 你好!

         很难完美的实现这个功能,首先Windows并非实时系统,你发出的指令不一定会马上的响应。即使你使用两个线程来分别执行,调度线程的也是操作系统,我们无法控制时间片的分配。

         你只能每隔一段时间同步一次,这样效果也不是很好啊。


    周雪峰
    2010年7月19日 5:26
    版主
  • 周大哥你说的对呀 ,  但是老板有这个变态的要求 ,愁得我头发都白了,我不知道该怎么跟他解释,他不懂windows 帮我想想办法吧.

    2010年7月19日 5:57
  • 真的没有办法解决了吗?各路大神显显灵,救救我吧~~~
    2010年7月19日 6:42
  • 你好!

         只能每隔一段时间同步一次,效果不怎么样,肯定要快进的现象。

         这个实际上相当难实现。他为什么要同步,主要是想干什么?


    周雪峰
    2010年7月19日 7:36
    版主
  • 有一个竖放的长方形屏幕,播放普通视频的话上面很大一部分就会空着,很难看,所以想用多个视频窗口填充,使其充满整个屏幕.

    2010年7月19日 8:14
  • 我考虑这么做,自定义事件子窗体播放视频完成后 谁先播完就通知其他未播放完成的窗体全部重播.这样做可行吗?
    2010年7月19日 8:16
  • 他的具体需求是什么?如果是类似“画中画”的功能 (也就是多个区域显示同一图像或视频),您又在使用 Windows 7,则可以用 Thumbnail and Preview API 实现 (类似于任务栏上的小 Media Player 窗口,与大的窗口的播放是完全同步的),如果是其他操作系统的话。。。有点困难,如果需要显示的区域位于同一个显示器上,那么,原理是利用 DirectX SDK 抓取 Windows Media Player 的 DX 区域,并每隔一段时间 (如 1/24s) 拷贝一次到指定区域,这里不能用 PrintWindow 函数,因为 PrintWindow 抓不到 DirectShow 图像。

    关于 Windows 7 缩略图和预览 API 的例子,参见 Microsoft All-in-One Code Framework。

    其他参考:

    http://blogs.microsoft.co.il/blogs/sasha/archive/2009/08/12/windows-7-taskbar-tabbed-thumbnails-and-previews-in-native-code.aspx
    http://blogs.microsoft.co.il/blogs/sasha/archive/2009/03/06/windows-7-taskbar-thumbnail-clip-and-custom-previews.aspx


    Mark Zhou
    2010年7月19日 8:17
  • 以其中一个窗体(如Form1)的this.axWindowsMediaPlayer1.Ctlcontrols.currentPosition为基准。设为静态double变量。
    让其它Form的this.axWindowsMediaPlayer1.Ctlcontrols.currentPosition = Form1的基准值。
    可以在每个窗体加个Timer,设置为10毫秒,来执行上面的代码。
    2010年7月19日 9:20
  • 我考虑这么做,自定义事件子窗体播放视频完成后 谁先播完就通知其他未播放完成的窗体全部重播.这样做可行吗?


    这样也不能完全同步,还是不能实现你的需要啊。

    大家的建议你都可以尝试。

    我感觉Windows7的那个预览窗口也并非总是和主窗体完全同步的

    你可以看看现在的播放器都是怎么处理这种情况的,当不是拉伸就是剪切啊。


    周雪峰
    2010年7月19日 10:47
    版主
  • Form1:
            private void Form1_Load(object sender, EventArgs e)
            {
                Form2 Form21 = new Form2();
                Form21.IsBase = true;
                Form21.Show();
                Form21.Text = "主";
                Form2 Form22 = new Form2();
                Form22.IsBase = false;
                Form22.Show();
                Form22.Text = "从";
                Form21.play(@"d:\clock.avi");
                Thread.Sleep(1500);
                Form22.play(@"d:\clock.avi");

    Form2:
        public partial class Form2 : Form
        {
            public Form2()
            {
                InitializeComponent();
            }
            public bool IsBase = true; // true表示以此窗体为基准。
            public static double basePosition = 0;
            private void Form2_Load(object sender, EventArgs e)
            {
                this.axWindowsMediaPlayer1.settings.setMode("loop", true);
            }
            public void play(string URL)
            {
                this.axWindowsMediaPlayer1.URL = URL;
                timer1.Enabled = true;
            }
            private void timer1_Tick(object sender, EventArgs e) // 10毫秒触发一次,或者更短。
            {
                if (this.IsBase)
                {
                    basePosition = this.axWindowsMediaPlayer1.Ctlcontrols.currentPosition;
                }
                else
                {
                    double temp = System.Math.Abs(this.axWindowsMediaPlayer1.Ctlcontrols.currentPosition - basePosition);
                    if (temp > 0.05) // 没具体研究过,听说每秒24帧,1/24=0.04167。
                    {
                        this.axWindowsMediaPlayer1.Ctlcontrols.currentPosition = basePosition;
                    }
                }
            }
        }

    2010年7月20日 7:13
  • 谢谢楼上的各位,谢谢纪元隆那么详细的代码

    我试过你的代码了,发现第二个窗口进度条是跟着同步了,但是主窗体没响应了,而且第二个窗口是黑色的,没有视频出现.CPU占用也很高,看来真没什么好方法了~~

    2010年7月20日 15:19
  • 我用C:\WINDOWS\clock.avi视频做的实验,两个窗口都可以正常播放。你的视频多大?我找个近似尺寸的试试。
    2010年7月21日 5:20