libvlc media player in C# (part 2)

原文 http://www.helyar.net/2009/libvlc-media-player-in-c-part-2/

I gave some simplified VLC media player code in part 1 to show how easy it was to do and how most wrapper libraries make a mountain out of a mole hill. In that entry, I briefly touched on using some classes to make it easier and safer to implement actual programs with this.

The first thing to do is write a wrapper for the exceptions, so that they are handled nicely in C#. For a program using the library, exceptions should be completely transparent and should be handled in the normal try/catch blocks without having to do anything like initialise them or check them.

Another thing to do is to move all of the initialisation functions into constructors and all of the release functions into destuctors or use the System.IDisposable interface.

Here is the code listing for the 4 classes used (VlcInstance, VlcMedia, VlcMediaPlayer and VlcException). Note that the first 3 of these are very similar and that the main difference is that the media player class has some extra functions for doing things like playing and pausing the content.

class VlcInstance : IDisposable
{
    internal IntPtr Handle;
 
    public VlcInstance(string[] args)
    {
        VlcException ex = new VlcException();
        Handle = LibVlc.libvlc_new(args.Length, args, ref ex.Ex);
        if (ex.IsRaised) throw ex;
    }
 
    public void Dispose()
    {
        LibVlc.libvlc_release(Handle);
    }
}
 
class VlcMedia : IDisposable
{
    internal IntPtr Handle;
 
    public VlcMedia(VlcInstance instance, string url)
    {
        VlcException ex = new VlcException();
        Handle = LibVlc.libvlc_media_new(instance.Handle, url, ref ex.Ex);
        if (ex.IsRaised) throw ex;
    }
 
    public void Dispose()
    {
        LibVlc.libvlc_media_release(Handle);
    }
}
 
class VlcMediaPlayer : IDisposable
{
    internal IntPtr Handle;
    private IntPtr drawable;
    private bool playing, paused;
 
    public VlcMediaPlayer(VlcMedia media)
    {
        VlcException ex = new VlcException();
        Handle = LibVlc.libvlc_media_player_new_from_media(media.Handle, ref ex.Ex);
        if (ex.IsRaised) throw ex;
    }
 
    public void Dispose()
    {
        LibVlc.libvlc_media_player_release(Handle);
    }
 
    public IntPtr Drawable
    {
        get
        {
            return drawable;
        }
        set
        {
            VlcException ex = new VlcException();
            LibVlc.libvlc_media_player_set_drawable(Handle, value, ref ex.Ex);
            if (ex.IsRaised) throw ex;
            drawable = value;
        }
    }
 
    public bool IsPlaying { get { return playing && !paused; } }
 
    public bool IsPaused { get { return playing && paused; } }
 
    public bool IsStopped { get { return !playing; } }
 
    public void Play()
    {
        VlcException ex = new VlcException();
        LibVlc.libvlc_media_player_play(Handle, ref ex.Ex);
        if (ex.IsRaised) throw ex;
 
        playing = true;
        paused = false;
    }
 
    public void Pause()
    {
        VlcException ex = new VlcException();
        LibVlc.libvlc_media_player_pause(Handle, ref ex.Ex);
        if (ex.IsRaised) throw ex;
 
        if (playing)
            paused ^= true;
    }
 
    public void Stop()
    {
        VlcException ex = new VlcException();
        LibVlc.libvlc_media_player_stop(Handle, ref ex.Ex);
        if (ex.IsRaised) throw ex;
 
        playing = false;
        paused = false;
    }
}
 
class VlcException : Exception
{
    internal libvlc_exception_t Ex;
 
    public VlcException() : base()
    {
        Ex = new libvlc_exception_t();
        LibVlc.libvlc_exception_init(ref Ex);
    }
 
    public bool IsRaised { get { return LibVlc.libvlc_exception_raised(ref Ex) != 0; } }
 
    public override string Message { get { return LibVlc.libvlc_exception_get_message(ref Ex); } }
}

Using these classes is even easier than before, can use proper exception handling (removed for brevity) and cleans up better at the end. In this example, I have added an OpenFileDialog, which is where the file is loaded.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
 
namespace MyLibVLC
{
    public partial class Form1 : Form
    {
        VlcInstance instance;
        VlcMediaPlayer player;
 
        public Form1()
        {
            InitializeComponent();
 
            openFileDialog1.FileName = "";
            openFileDialog1.Filter = "MPEG|*.mpg|AVI|*.avi|All|*.*";
 
            string[] args = new string[] {
                "-I", "dummy", "--ignore-config",
                @"--plugin-path=C:\Program Files (x86)\VideoLAN\VLC\plugins",
                "--vout-filter=deinterlace", "--deinterlace-mode=blend"
            };
 
            instance = new VlcInstance(args);
            player = null;
        }
 
        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            if(player != null) player.Dispose();
            instance.Dispose();
        }
 
        private void Open_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() != DialogResult.OK)
                return;
 
            using (VlcMedia media = new VlcMedia(instance, openFileDialog1.FileName))
            {
                if (player != null) player.Dispose();
                player = new VlcMediaPlayer(media);
            }
 
            player.Drawable = panel1.Handle;
        }
 
        private void Play_Click(object sender, EventArgs e)
        {
            player.Play();
        }
 
        private void Pause_Click(object sender, EventArgs e)
        {
            player.Pause();
        }
 
        private void Stop_Click(object sender, EventArgs e)
        {
            player.Stop();
        }
    }
}

Update:

I have just corrected a minor bug (the wrong release function being called on the player handle) and uploaded the full Visual Studio 2005 project. You can download the full project here (or see 1.1.2 version below). It comes with the libvlc.dll and libvlccore.dll for VLC 1.0.1 in the bin\x86\Debug directory so if you have a version other than this, just overwrite those files.

Update for VLC 1.1.2:

You can now download the VLC 1.1.2 compatible version. There were some changes to the way libvlc handles exceptions that needed to be corrected. Other than that, there were a couple of minor function name changes.

Please use these posts as a starting point to use your own code though. These posts are intended to stoppeople from being reliant on the already existing, large, overcomplicated and quickly outdated libraries. They are not intended to be just another library for people to blindly use without understanding how it works. You can use this to learn how to write your own native interop code on a well designed library then adapt it for your own changes and keep it up to date with whichever version of VLC you want. This also means you never have to use the terrible code on pinvoke.net for other libraries, as you can write your own from the original documentation and it will almost always be better.

Bugfix: VlcException should use Marshal.PtrToStringAnsi not Marshal.PtrToStringAuto

时间: 2024-09-19 10:15:10

libvlc media player in C# (part 2)的相关文章

libvlc media player in C# (part 1)

原文 http://www.helyar.net/2009/libvlc-media-player-in-c/ There seems to be a massive misconception about using VLC inside an application and many, many large wrapper libraries have been written. These are often harder to use than libvlc itself, buggy

MFC使用window media player时遇到的问题

问题描述 MFC使用window media player时遇到的问题 MFC调用media player控件来播放视频,在xp和win7下都能播放,开始时怎么使用都没问题,但一段时间后在xp下切换视频时,调试到这一句m_player.put_url(strFilename)出现内存错误win7下完全没问题,请教大家帮忙解决一下,其中各个变量和指针都看过了,都没问题,调试了很久一直没解决 解决方案 出错的时候好像m_player这个对象不正确了.也可能media player控件本身挂了. 解决

如何在网页中嵌入Media player 播放流媒体文件

媒体|网页 Media Player两种版本播放器的嵌入代码,有相关说明(默认0为否,-1或1为是)不过代码还不全面,没有判断浏览器版本的参数程序代码: <object classid="clsid:22D6F312-B0F6-11D0-94AB-0080C74C7E95" id="MediaPlayer1" width="286" height="225"><param name="AudioSt

net 页面怎样内嵌media player视频窗口

页面 <script language=javascript defer> var volv=phx.settings.volume; setInterval("if(phx.playState==3){time.innerText=phx.controls.currentPositionString+'|'+ phx.currentMedia.durationString}",1000); setInterval("if(phx.playState==3){it

媒体播放器Media Player Classic

Media Player Classic Home Cinema,简称MPC-HC,是一款简洁的媒体播放器,Media Player Classic 的后续版本,有32位元和64位元版本.Media Player Classic 是由名为 "Gabest" 的程序员建立,现在他仍然有维护这个程序. Gabest 原先是以不公开源代码的方式开发 Media Player Classic,但后来他开放了 Media Player Classic 的源代码. 目前mpc-hc是一款开源软件,

Media Player Classic Home Cinema媒体播放器

Media Player Classic Home Cinema,简称MPC-HC,是一款简洁的媒体播放器,Media Player Classic 的后续版本,有32位元和64位元版本.Media Player Classic 是由名为 "Gabest" 的程序员建立,现在他仍然有维护这个程序. Gabest 原先是以不公开源代码的方式开发 Media Player Classic,但后来他开放了 Media Player Classic 的源代码. 目前mpc-hc是一款开源软件,

Windows Media Player界面的实现

一.简介 SYGUI是一个基于功能扩展的MFC界面库,我在以前的文章中介绍了如何使用该界面库来实现VC界面,在本文中将向大家介绍利用SYGUI4.0所提供的新功能来实现类似Windows Media Player的界面定制功能.这里所指的界面定制功能是指在不修改程序代码的情况下允许为程序设计各种具有不同外观风格的程序界面.例如本文所附的例子程序包含了如下图所示的三种不同的界面,三种界面可通过界面上的外观选择按钮进行动态切换: 图一 例子程序运行时的三种界面 当然,通过界面定制还可以为例子程序设计

Windows Media Player 12的新特性

我们已经介绍了一些 Windows 7 的新特性和新功能了,这次我们来看看 Windows Media Player 12 吧,Windows Media Player 仍然是 Windows 中的一个重要组件,本以为 Zune 会代替 Windows Media Player,题外话:Zune 软件的社会化功能确实挺有意思的,比如:Zune 的 Social Card,和 MixView 都很不错. Windows Media Player 12 的界面恐怕是最显著的变化了,与 Windows

WinCE 4.2下轻松调用Windows Media Player控件

小弟是个刚入门的菜鸟,现在大家都在做嵌入式开发了,所以我也来凑凑热闹.菜鸟就是菜鸟,这不,现在想在 WinCE4.2 下播放 wma.mp3 音乐,可是连个 Winodws Media Player 控件都不知道该怎么调用.大家可不要笑啊,以前我在 Winodws2000 平台下,感觉调用这个控件非常简单,可是在 WinCE4.2 平台下就没辙了.为什么呢?原因就是基于 WinCE4.2 平台的程序开发要在 Windows2000 等平台上做,可是在 Windows2000 平台上调出来的 Wi