Воспроизведение файлов в формате OGG (аудио и видео)

При разработке очередного ПО столкнулся с проблемой использования в коммерческих целях известные форматы видео и аудио. Например, mp3, mp4 и т.п. По google-в наткнулся на абсолютно свободный формат — ogg. Этот формат позволяет хранить видео и аудио контент. Решил остановиться на нем, но тут возникла следующая проблема: для разработки самого простого проигрывателя для данного формата необходимо в систему установить свободный проигрыватель VideoLan и использовать его или как ActiveX или напрямую его библиотеки и плагины. Это не очень удобно, а точнее совсем не удобно! После нескольких дней поисков и ковыряний решение было найдено.

И так, для создания своего проигрывателя ogg файлов нам необходимо:

1. Сделать класс:

using System;
using System.Runtime.InteropServices;

namespace MyLibVLC
{
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    struct libvlc_exception_t
    {
        public int b_raised;
        public int i_code;
        [MarshalAs(UnmanagedType.LPStr)]
        public string psz_message;
    }
	
 	public enum VlcState
 	{
 	    NothingSpecial = 0,
 	    Opening,
 	    Buffering,
 	    Playing,
 	    Paused,
 	    Stopped,
 	    Forward,
 	    Backward,
 	    Ended,
 	    Error
 	}

    static class LibVlc
    {
        #region core
        [DllImport("libvlc")]
        public static extern IntPtr libvlc_new(int argc, [MarshalAs(UnmanagedType.LPArray,
          ArraySubType = UnmanagedType.LPStr)] string[] argv, ref libvlc_exception_t ex);

        [DllImport("libvlc")]
        public static extern void libvlc_release(IntPtr instance);
        #endregion

        #region media
        [DllImport("libvlc")]
        public static extern IntPtr libvlc_media_new(IntPtr p_instance,
          [MarshalAs(UnmanagedType.LPStr)] string psz_mrl, ref libvlc_exception_t p_e);

        [DllImport("libvlc")]
        public static extern void libvlc_media_release(IntPtr p_meta_desc);

        #endregion

        #region media player
        [DllImport("libvlc")]
        public static extern IntPtr libvlc_media_player_new_from_media(IntPtr media,
          ref libvlc_exception_t ex);

        [DllImport("libvlc")]
        public static extern void libvlc_media_player_release(IntPtr player);

        [DllImport("libvlc")]
        public static extern void libvlc_media_player_set_drawable(IntPtr player, IntPtr drawable,
          ref libvlc_exception_t p_e);

        [DllImport("libvlc")]
        public static extern IntPtr libvlc_media_player_get_media(IntPtr player, ref libvlc_exception_t ex);

        [DllImport("libvlc")]
        public static extern void libvlc_media_player_set_media(IntPtr player, IntPtr media, ref libvlc_exception_t ex);

        [DllImport("libvlc")]
        public static extern void libvlc_media_player_play(IntPtr player, ref libvlc_exception_t ex);

        [DllImport("libvlc")]
        public static extern void libvlc_media_player_pause(IntPtr player, ref libvlc_exception_t ex);

        [DllImport("libvlc")]
        public static extern void libvlc_media_player_stop(IntPtr player, ref libvlc_exception_t ex);

        [DllImport("libvlc")]
        public static extern long libvlc_media_player_get_length(IntPtr player, ref libvlc_exception_t ex);

        [DllImport("libvlc")]
        public static extern float libvlc_media_player_get_position(IntPtr player, ref libvlc_exception_t ex);
        
        [DllImport("libvlc")]
    	internal static extern void libvlc_media_player_set_position(IntPtr player, float position, ref libvlc_exception_t ex);

        [DllImport("libvlc")]
        internal static extern long libvlc_media_player_get_time(IntPtr player, ref libvlc_exception_t ex);

        [DllImport("libvlc")]
        internal static extern void libvlc_media_player_set_time(IntPtr player, long time, ref libvlc_exception_t ex);


        [DllImport("libvlc")]
        internal static extern VlcState libvlc_media_player_get_state(IntPtr player, ref libvlc_exception_t ex);
        #endregion

        #region exception
        [DllImport("libvlc")]
        public static extern void libvlc_exception_init(ref libvlc_exception_t p_exception);

        [DllImport("libvlc")]
        public static extern int libvlc_exception_raised(ref libvlc_exception_t p_exception);

        [DllImport("libvlc")]
        public static extern string libvlc_exception_get_message(ref libvlc_exception_t p_exception);
        #endregion
    }

    class VlcInstance : IDisposable
    {
        internal IntPtr Handle;

        /// <summary>
        /// Инициализация библиотеки libvlc.dll и плагинов. Необходимо передать полный путь к папке plugins. Например: "C:\Program Files\VideoLAN\VLC\Plugins"
        /// </summary>
        /// <param name="plugins_path"></param>
        public VlcInstance(string plugins_path)
        {
            VlcException ex = new VlcException();
            string[] args = new string[] {"-I", "dummy", "--ignore-config", @"--plugin-path=" + plugins_path, "--vout-filter=deinterlace" };
            Handle = LibVlc.libvlc_new(args.Length, args, ref ex.Ex);
            if (ex.IsRaised) throw ex;
        }

        /// <summary>
        /// Вызываем для уничтожения инициализации библиотеки libvlc.dll и плагинов.
        /// </summary>
        public void Dispose()
        {
            LibVlc.libvlc_release(Handle);
        }
    }

    class VlcMedia : IDisposable
    {
        internal IntPtr Handle;

        /// <summary>
        /// Создаем объект media. Передаем объект типа VlcInstance и полный путь к файлу мультимедиа. Например: VlcMedia media = new VlcMedia(VlcInstance, "путь_и_имя_файла")
        /// </summary>
        /// <param name="instance"></param>
        /// <param name="url"></param>
        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;
        }

        internal VlcMedia(IntPtr handle)
        {
            this.Handle = handle;
        }

        /// <summary>
        /// Уничтожаем объект media.
        /// </summary>
        public void Dispose()
        {
            LibVlc.libvlc_media_release(Handle);
        }
    }

    class VlcMediaPlayer : IDisposable
    {
        internal IntPtr Handle;
        private IntPtr drawable;
        private bool playing, paused;

        /// <summary>
        /// Создаем проигрыватель. Передаем обект типа VlcMedia.  
        /// </summary>
        /// <param name="media"></param>
        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;
        }

        /// <summary>
        /// Уничтожаем проигрыватель.
        /// </summary>
        public void Dispose()
        {
            LibVlc.libvlc_media_player_release(Handle);
        }

        /// <summary>
        /// Устанавливаем область воспроизведения видео. Приравниваем handle нашей области воспроизведения.
        /// </summary>
        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 VlcMedia Media
        {
            get
            {
                VlcException ex = new VlcException();
                IntPtr media = LibVlc.libvlc_media_player_get_media(Handle, ref ex.Ex);
                if (ex.IsRaised) throw ex;
                return new VlcMedia(media);
            }
            set
            {
                VlcException ex = new VlcException();
                LibVlc.libvlc_media_player_set_media(Handle, value.Handle, ref ex.Ex);
                if (ex.IsRaised) throw ex;
            }
        }

        public bool IsPlaying { get { return playing && !paused; } }

        public bool IsPaused { get { return playing && paused; } }

        public bool IsStopped { get { return !playing; } }

        /// <summary>
        /// Воспроизведение
        /// </summary>
        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;
        }

        /// <summary>
        /// Пауза
        /// </summary>
        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;
        }

        /// <summary>
        /// Стоп
        /// </summary>
        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;
        }

        public long Length()
        {
            VlcException ex = new VlcException();
            long lng = LibVlc.libvlc_media_player_get_length(Handle, ref ex.Ex);
            if (ex.IsRaised) throw ex;
            return lng;
        }

        public float GetPosition()
        {
            VlcException ex = new VlcException();
            float pos = LibVlc.libvlc_media_player_get_position(Handle, ref ex.Ex);
            if (ex.IsRaised) throw ex;
            return pos;
        }

        public void SetPosition(float pos)
        {
            VlcException ex = new VlcException();
            LibVlc.libvlc_media_player_set_position(Handle, pos, ref ex.Ex);
            if (ex.IsRaised) throw ex; 
        }

        public long GetTime()
        {
            VlcException ex = new VlcException();
            long time = LibVlc.libvlc_media_player_get_time(Handle, ref ex.Ex);
            if (ex.IsRaised) throw ex;
            return time;
        }

        public void SetTime(long time)
        {
            VlcException ex = new VlcException();
            LibVlc.libvlc_media_player_set_time(Handle, time, ref ex.Ex);
            if (ex.IsRaised) throw ex; 
        }

        public VlcState GetState()
        {
            VlcException ex = new VlcException();
            VlcState state = LibVlc.libvlc_media_player_get_state(Handle, ref ex.Ex);
            if (ex.IsRaised) throw ex;
            return state;
        }
    }

    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); } }
    }
}


2. Скачать вот эти библиотеки и положить в папку с нашим проектом:

libvlc.dll
libvlccore.dll

3. Скачать архив с минимальным набором плагинов необходимы для проигрывания аудио (Vorvis)и видео (Theora):

Plugins.7z

Содержимое данного архива можно распаковать куда Вам будет удобно, путь к папке мы будем передавать в коде параметром.

Полный архив (пример)

Хочу обратить внимание, что плагины и dll-ки надо использовать именно эти. Я их очень долго подбирал из разных версий VideoLAN-а. И так как это open source проект, то довольно часто происходит изменение названий функции в dll.

Будут вопросы пишите, всех благ!

Комментарии (4)

RSS свернуть / развернуть
+
+1
В данный момент прикручиваем проигрыватель к Windows Mobile, Windows Phone 7.
avatar

mastersoftna

  • 10 июня 2011, 10:25
+
+2
Спасибо автору за интересный и полезный материал.
Некоторые замечания и дополнения:
При компиляции может возникнуть ошибка о расбалансировке стэка и тд. В таком случае надо импортировать функции из dll с директивой [DllImport(LIBVLC, CallingConvention = CallingConvention.Cdecl)]
Следующий недостаток — не воспроизводятся звуковые файлы с русскими символами в путях.
Помогло следующее:
[DllImport(LIBVLC, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr libvlc_media_new(IntPtr p_instance,
[MarshalAs(UnmanagedType.LPArray)] byte[] psz_mrl, ref libvlc_exception_t p_e);
avatar

Jungle

  • 01 июля 2011, 12:07
+
+2
Забыл добавить: путь к файлу следует передавать как Encoding.UTF8.GetBytes(FileName).
avatar

Jungle

  • 01 июля 2011, 12:09
+
0
Skajite pojaluysta kak vsyo eto rabotaet,chto nado essho, chtobi ya mog iz interfeysa c# dat play,pause i stop? Ya dabavil v winform panel1 no nechego ne preisxodit,i oshibki netu…
avatar

emgrig

  • 05 декабря 2011, 11:29

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.