2f107db...5202af9
This commit is contained in:
@@ -0,0 +1,298 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Barotrauma.Sounds;
|
||||
|
||||
namespace Barotrauma.Media
|
||||
{
|
||||
public class Video : IDisposable
|
||||
{
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate IntPtr LibVLCVideoLockCb(IntPtr opaque, IntPtr planes);
|
||||
private static LibVLCVideoLockCb VideoLockDelegate;
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void LibVLCVideoUnlockCb(IntPtr opaque, IntPtr picture, IntPtr planes);
|
||||
private static LibVLCVideoUnlockCb VideoUnlockDelegate;
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void LibVLCVideoDisplayCb(IntPtr opaque, IntPtr picture);
|
||||
private static LibVLCVideoDisplayCb VideoDisplayDelegate;
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void LibVLCAudioPlayCb(IntPtr data, IntPtr samples, uint count, long pts);
|
||||
private static LibVLCAudioPlayCb AudioPlayDelegate;
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void LibVLCAudioPauseCb(IntPtr data, long pts);
|
||||
private static LibVLCAudioPauseCb AudioPauseDelegate;
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void LibVLCAudioResumeCb(IntPtr data, long pts);
|
||||
private static LibVLCAudioResumeCb AudioResumeDelegate;
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void LibVLCAudioFlushCb(IntPtr data, long pts);
|
||||
private static LibVLCAudioFlushCb AudioFlushDelegate;
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void LibVLCAudioDrainCb(IntPtr data);
|
||||
private static LibVLCAudioDrainCb AudioDrainDelegate;
|
||||
|
||||
|
||||
private static IntPtr lib = IntPtr.Zero;
|
||||
|
||||
private static Dictionary<int, Video> videos;
|
||||
private static int latestVideoId;
|
||||
public static void Init()
|
||||
{
|
||||
if (lib == IntPtr.Zero)
|
||||
{
|
||||
string[] parameters = {
|
||||
//"--no-xlib"
|
||||
};
|
||||
|
||||
lib = LibVlcWrapper.LibVlcMethods.libvlc_new(parameters.Length, parameters);
|
||||
|
||||
videos = new Dictionary<int, Video>();
|
||||
latestVideoId = 0;
|
||||
|
||||
VideoLockDelegate = VideoLockCallback;
|
||||
VideoUnlockDelegate = VideoUnlockCallback;
|
||||
VideoDisplayDelegate = VideoDisplayCallback;
|
||||
|
||||
AudioPlayDelegate = AudioPlayCallback;
|
||||
AudioPauseDelegate = AudioPauseCallback;
|
||||
AudioResumeDelegate = AudioResumeCallback;
|
||||
AudioFlushDelegate = AudioFlushCallback;
|
||||
AudioDrainDelegate = AudioDrainCallback;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Close()
|
||||
{
|
||||
if (lib != IntPtr.Zero)
|
||||
{
|
||||
List<int> keys = videos.Keys.ToList();
|
||||
foreach (int key in keys)
|
||||
{
|
||||
videos[key].Dispose();
|
||||
}
|
||||
|
||||
LibVlcWrapper.LibVlcMethods.libvlc_free(lib);
|
||||
|
||||
lib = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
private int videoId;
|
||||
private IntPtr unmanagedData;
|
||||
|
||||
private IntPtr media;
|
||||
private IntPtr mediaPlayer;
|
||||
private Texture2D texture;
|
||||
private byte[] textureData;
|
||||
private object mutex;
|
||||
private VideoSound sound;
|
||||
|
||||
/*private IntPtr videoLockDelegate;
|
||||
private IntPtr videoUnlockDelegate;
|
||||
private IntPtr videoDisplayDelegate;*/
|
||||
|
||||
public uint Width { get; private set; }
|
||||
public uint Height { get; private set; }
|
||||
|
||||
public Video(GraphicsDevice graphicsDevice,SoundManager soundManager,string filename,uint width,uint height)
|
||||
{
|
||||
Init();
|
||||
|
||||
mutex = new object();
|
||||
sound = new VideoSound(soundManager, filename, 44100, this);
|
||||
videos.Add(latestVideoId, this);
|
||||
videoId = latestVideoId; latestVideoId++;
|
||||
|
||||
/*using (var stream = File.OpenRead(filename))
|
||||
{*/
|
||||
byte[] filenameBytes = Encoding.UTF8.GetBytes(filename);
|
||||
byte[] filenameBytesNullTerminated = new byte[filenameBytes.Length + 1];
|
||||
filenameBytesNullTerminated[filenameBytes.Length] = 0;
|
||||
Array.Copy(filenameBytes, filenameBytesNullTerminated, filenameBytes.Length);
|
||||
media = LibVlcWrapper.LibVlcMethods.libvlc_media_new_path(lib, filenameBytesNullTerminated);
|
||||
LibVlcWrapper.LibVlcMethods.libvlc_media_parse(media);
|
||||
|
||||
mediaPlayer = LibVlcWrapper.LibVlcMethods.libvlc_media_player_new(lib);
|
||||
LibVlcWrapper.LibVlcMethods.libvlc_media_player_set_media(mediaPlayer, media);
|
||||
//LibVlcWrapper.LibVlcMethods.libvlc_media_release(media);
|
||||
|
||||
//LibVlcWrapper.LibVlcMethods.libvlc_video_get_size(mediaPlayer, 0, out width, out height);
|
||||
texture = new Texture2D(graphicsDevice, (int)width, (int)height);
|
||||
Width = width; Height = height;
|
||||
|
||||
unmanagedData = Marshal.AllocHGlobal(sizeof(int)*2+(int)(width*height*3));
|
||||
int[] arr = { videoId, 1 };
|
||||
Marshal.Copy(arr, 0, unmanagedData, 2);
|
||||
textureData = new byte[width * height * 3];
|
||||
for (int i = 0; i < width*height*3; i++)
|
||||
{
|
||||
textureData[i] = 0;
|
||||
}
|
||||
|
||||
IntPtr videoLockDelegatePtr = Marshal.GetFunctionPointerForDelegate(VideoLockDelegate);
|
||||
IntPtr videoUnlockDelegatePtr = Marshal.GetFunctionPointerForDelegate(VideoUnlockDelegate);
|
||||
IntPtr videoDisplayDelegatePtr = Marshal.GetFunctionPointerForDelegate(VideoDisplayDelegate);
|
||||
LibVlcWrapper.LibVlcMethods.libvlc_video_set_callbacks(mediaPlayer, videoLockDelegatePtr, videoUnlockDelegatePtr, videoDisplayDelegatePtr, unmanagedData);
|
||||
LibVlcWrapper.LibVlcMethods.libvlc_video_set_format(mediaPlayer, Encoding.UTF8.GetBytes("RV24"), (int)width, (int)height, (int)width * 3);
|
||||
|
||||
IntPtr audioPlayDelegatePtr = Marshal.GetFunctionPointerForDelegate(AudioPlayDelegate);
|
||||
IntPtr audioPauseDelegatePtr = Marshal.GetFunctionPointerForDelegate(AudioPauseDelegate);
|
||||
IntPtr audioResumeDelegatePtr = Marshal.GetFunctionPointerForDelegate(AudioResumeDelegate);
|
||||
IntPtr audioFlushDelegatePtr = Marshal.GetFunctionPointerForDelegate(AudioFlushDelegate);
|
||||
IntPtr audioDrainDelegatePtr = Marshal.GetFunctionPointerForDelegate(AudioDrainDelegate);
|
||||
|
||||
LibVlcWrapper.LibVlcMethods.libvlc_audio_set_callbacks(mediaPlayer, audioPlayDelegatePtr, audioPauseDelegatePtr, audioResumeDelegatePtr, audioFlushDelegatePtr, audioDrainDelegatePtr, unmanagedData);
|
||||
LibVlcWrapper.LibVlcMethods.libvlc_audio_set_format(mediaPlayer, Encoding.UTF8.GetBytes("S16N"), 44100, 2);
|
||||
|
||||
LibVlcWrapper.LibVlcMethods.libvlc_audio_set_delay(mediaPlayer, 0);
|
||||
|
||||
LibVlcWrapper.LibVlcMethods.libvlc_media_player_play(mediaPlayer);
|
||||
|
||||
//}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
LibVlcWrapper.LibVlcMethods.libvlc_media_player_stop(mediaPlayer);
|
||||
|
||||
Monitor.Enter(mutex);
|
||||
//just waiting for callbacks to be done
|
||||
Monitor.Exit(mutex);
|
||||
|
||||
Marshal.FreeHGlobal(unmanagedData);
|
||||
|
||||
sound.Dispose();
|
||||
|
||||
LibVlcWrapper.LibVlcMethods.libvlc_media_release(media);
|
||||
LibVlcWrapper.LibVlcMethods.libvlc_media_player_release(mediaPlayer);
|
||||
|
||||
texture.Dispose();
|
||||
|
||||
videos.Remove(videoId);
|
||||
}
|
||||
|
||||
public bool IsPlaying
|
||||
{
|
||||
get
|
||||
{
|
||||
return LibVlcWrapper.LibVlcMethods.libvlc_media_player_is_playing(mediaPlayer)!=0;
|
||||
}
|
||||
}
|
||||
|
||||
public Texture2D GetTexture()
|
||||
{
|
||||
Monitor.Enter(mutex);
|
||||
|
||||
int[] arr = { -1 };
|
||||
IntPtr changedPtr = (IntPtr)(unmanagedData.ToInt64() + sizeof(int));
|
||||
Marshal.Copy(changedPtr, arr, 0, 1);
|
||||
|
||||
if (arr[0]!=0)
|
||||
{
|
||||
IntPtr colorLocation = (IntPtr)(unmanagedData.ToInt64() + sizeof(int) * 2);
|
||||
Marshal.Copy(colorLocation, textureData, 0, (int)(Width * Height * 3));
|
||||
Color[] colors = new Color[Width * Height];
|
||||
for (int y = 0; y < Height;y++)
|
||||
{
|
||||
for (int x = 0; x < Width;x++)
|
||||
{
|
||||
colors[x + y * Width] = new Color(textureData[3 * (x + y * Width) + 0],
|
||||
textureData[3 * (x + y * Width) + 1],
|
||||
textureData[3 * (x + y * Width) + 2],
|
||||
(byte)255);
|
||||
}
|
||||
}
|
||||
texture.SetData(colors);
|
||||
arr[0] = 0;
|
||||
Marshal.Copy(arr, 0, changedPtr, 1);
|
||||
}
|
||||
|
||||
if (!sound.IsPlaying()) videos[videoId].sound.Play();
|
||||
|
||||
Monitor.Exit(mutex);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
static IntPtr VideoLockCallback(IntPtr opaque, IntPtr planes)
|
||||
{
|
||||
int[] arr = { -1 };
|
||||
Marshal.Copy(opaque, arr, 0, 1);
|
||||
int mutexIndex = arr[0];
|
||||
|
||||
Monitor.Enter(videos[mutexIndex].mutex);
|
||||
|
||||
IntPtr unmanagedData = (IntPtr)(opaque.ToInt64() + sizeof(int) * 2);
|
||||
IntPtr[] ptrPtr = { unmanagedData };
|
||||
Marshal.Copy(ptrPtr, 0, planes, 1);
|
||||
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
static void VideoUnlockCallback(IntPtr opaque, IntPtr picture, IntPtr planes)
|
||||
{
|
||||
int[] arr = { -1 };
|
||||
Marshal.Copy(opaque, arr, 0, 1);
|
||||
int mutexIndex = arr[0];
|
||||
arr[0] = 1;
|
||||
IntPtr changedPtr = (IntPtr)(opaque.ToInt64() + sizeof(int));
|
||||
Marshal.Copy(arr, 0, changedPtr, 1);
|
||||
|
||||
Monitor.Exit(videos[mutexIndex].mutex);
|
||||
}
|
||||
|
||||
static void VideoDisplayCallback(IntPtr opaque,IntPtr picture)
|
||||
{
|
||||
//Assert(picture == IntPtr.Zero);
|
||||
}
|
||||
|
||||
static void AudioPlayCallback(IntPtr data, IntPtr samples, uint count, long pts)
|
||||
{
|
||||
short[] buf = new short[count*2];
|
||||
Marshal.Copy(samples, buf, 0, (int)count*2);
|
||||
int[] arr = { -1 };
|
||||
Marshal.Copy(data, arr, 0, 1);
|
||||
int mutexIndex = arr[0];
|
||||
|
||||
Monitor.Enter(videos[mutexIndex].mutex);
|
||||
|
||||
videos[mutexIndex].sound.Enqueue(buf);
|
||||
|
||||
Monitor.Exit(videos[mutexIndex].mutex);
|
||||
}
|
||||
|
||||
static void AudioPauseCallback(IntPtr data, long pts)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void AudioResumeCallback(IntPtr data, long pts)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void AudioFlushCallback(IntPtr data, long pts)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void AudioDrainCallback(IntPtr data)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user